sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1752158 [6/6] - in /sis/branches/JDK8/core/sis-feature/src: main/java/org/apache/sis/feature/builder/ main/java/org/apache/sis/internal/feature/ test/java/org/apache/sis/feature/builder/ test/java/org/apache/sis/internal/feature/ test/java...
Date Mon, 11 Jul 2016 13:29:44 GMT
Copied: sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/builder/PropertyTypeBuilder.java (from r1751946, sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/internal/feature/FeatureTypeBuilder.java)
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/builder/PropertyTypeBuilder.java?p2=sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/builder/PropertyTypeBuilder.java&p1=sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/internal/feature/FeatureTypeBuilder.java&r1=1751946&r2=1752158&rev=1752158&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/internal/feature/FeatureTypeBuilder.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/builder/PropertyTypeBuilder.java [UTF-8] Mon Jul 11 13:29:44 2016
@@ -14,1481 +14,139 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.sis.internal.feature;
+package org.apache.sis.feature.builder;
 
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.Locale;
 import org.opengis.util.GenericName;
-import org.opengis.util.NameFactory;
-import org.opengis.util.FactoryException;
-import org.opengis.referencing.crs.CoordinateReferenceSystem;
-import org.apache.sis.feature.AbstractOperation;
-import org.apache.sis.feature.DefaultAssociationRole;
-import org.apache.sis.feature.DefaultAttributeType;
-import org.apache.sis.feature.DefaultFeatureType;
-import org.apache.sis.feature.FeatureOperations;
-import org.apache.sis.internal.system.DefaultFactories;
-import org.apache.sis.internal.util.CollectionsExt;
-import org.apache.sis.util.CorruptedObjectException;
 import org.apache.sis.util.resources.Errors;
-import org.apache.sis.util.ArraysExt;
-import org.apache.sis.util.Classes;
-
-// Branch-dependent imports
-import java.util.Objects;
 import org.opengis.feature.AttributeType;
-import org.opengis.feature.Feature;
 import org.opengis.feature.FeatureType;
 import org.opengis.feature.PropertyType;
 import org.opengis.feature.FeatureAssociationRole;
 
 
 /**
- * Helper class for the creation of {@link FeatureType} instances.
- * This builder can create the arguments to be given to the
- * {@linkplain DefaultFeatureType#DefaultFeatureType feature type constructor}
- * from simpler parameters given to this builder.
+ * Describes one property of the {@code FeatureType} to be built by an {@code FeatureTypeBuilder}.
+ * A different instance of {@code PropertyTypeBuilder} exists for each property to describe.
+ * Those instances can be created by:
  *
- * <p>{@code FeatureTypeBuilder} should be short lived.
- * After the {@code FeatureType} has been created, the builder should be discarded.</p>
+ * <ul>
+ *   <li>{@link FeatureTypeBuilder#addAttribute(Class)}</li>
+ *   <li>{@link FeatureTypeBuilder#addAttribute(AttributeType)} for using an existing attribute as a template</li>
+ *   <li>{@link FeatureTypeBuilder#addAssociation(FeatureType)}</li>
+ *   <li>{@link FeatureTypeBuilder#addAssociation(GenericName)}</li>
+ *   <li>{@link FeatureTypeBuilder#addAssociation(FeatureAssociationRole)} for using an existing association as a template</li>
+ * </ul>
  *
  * @author  Johann Sorel (Geomatys)
  * @author  Martin Desruisseaux (Geomatys)
- * @since   0.7
+ * @since   0.8
  * @version 0.8
  * @module
- *
- * @see org.apache.sis.parameter.ParameterBuilder
  */
-public class FeatureTypeBuilder extends FeatureElementBuilder {
-    /**
-     * The factory to use for creating names.
-     */
-    private final NameFactory nameFactory;
-
-    /**
-     * Builders for the properties (attributes, associations or operations) of this feature.
-     */
-    private final List<Property> properties;
-
-    /**
-     * The parent of the feature to create. By default, new features have no parent.
-     */
-    private final List<FeatureType> superTypes;
-
+abstract class PropertyTypeBuilder extends TypeBuilder {
     /**
-     * Whether the feature type is abstract. The default value is {@code false}.
-     *
-     * @see #isAbstract()
-     * @see #setAbstract(boolean)
+     * The feature type builder instance that created this {@code PropertyTypeBuilder}.
      */
-    private boolean isAbstract;
+    final FeatureTypeBuilder owner;
 
     /**
-     * The default scope to use when {@link #name(String, String)} is invoked with a null scope.
+     * The minimum number of property values.
+     * The default value is 1, unless otherwise specified by {@link #setDefaultCardinality(int, int)}.
      *
-     * @see #getDefaultScope()
-     * @see #setDefaultScope(String)
+     * @see #setCardinality(int, int)
      */
-    private String defaultScope;
+    int minimumOccurs;
 
     /**
-     * The default minimum number of property values.
+     * The maximum number of property values.
+     * The default value is 1, unless otherwise specified by {@link #setDefaultCardinality(int, int)}.
      *
-     * @see #setDefaultCardinality(int, int)
+     * @see #setCardinality(int, int)
      */
-    private int defaultMinimumOccurs;
+    int maximumOccurs;
 
     /**
-     * The default maximum number of property values.
-     *
-     * @see #setDefaultCardinality(int, int)
-     */
-    private int defaultMaximumOccurs;
-
-    /**
-     * An optional prefix or suffix to insert before or after the {@linkplain FeatureOperations#compound compound key}
-     * named {@code "@identifier"}.
-     */
-    private String idPrefix, idSuffix;
-
-    /**
-     * The separator to insert between each single component in a {@linkplain FeatureOperations#compound compound key}
-     * named {@code "@identifier"}. This is ignored if {@link #identifierCount} is zero.
-     */
-    private String idDelimiter;
-
-    /**
-     * Number of attribute that have been flagged as an identifier component.
-     *
-     * @see Attribute.Role#IDENTIFIER_COMPONENT
-     * @see AttributeConvention#IDENTIFIER_PROPERTY
-     */
-    private int identifierCount;
-
-    /**
-     * The default geometry attribute, or {@code null} if none.
-     *
-     * @see Attribute.Role#DEFAULT_GEOMETRY
-     * @see AttributeConvention#GEOMETRY_PROPERTY
-     */
-    private Attribute<?> defaultGeometry;
-
-    /**
-     * The object created by this builder, or {@code null} if not yet created.
+     * The attribute or association created by this builder, or {@code null} if not yet created.
      * This field must be cleared every time that a setter method is invoked on this builder.
      */
-    private transient FeatureType feature;
-
-    /**
-     * Creates a new builder instance using the default name factory.
-     */
-    public FeatureTypeBuilder() {
-        this(null, null, null);
-    }
+    private transient PropertyType property;
 
     /**
-     * Creates a new builder instance using the given feature type as a template.
+     * Creates a new {@code PropertyType} builder initialized to the values of an existing property.
      *
-     * @param template  an existing feature type to use as a template, or {@code null} if none.
+     * @param owner     the builder of the {@code FeatureType} for which to add this property.
+     * @param template  an existing property to use as a template, or {@code null} if none.
      */
-    public FeatureTypeBuilder(final FeatureType template) {
-        this(template, null, null);
+    PropertyTypeBuilder(final FeatureTypeBuilder owner, final PropertyType template) {
+        super(template, owner.getLocale());
+        this.owner    = owner;
+        minimumOccurs = owner.defaultMinimumOccurs;
+        maximumOccurs = owner.defaultMaximumOccurs;
+        property      = template;
     }
 
     /**
-     * Creates a new builder instance using the given name factory, template and locale for formatting error messages.
+     * Sets the minimum and maximum number of property values. Those numbers must be equal or greater than zero.
      *
-     * @param template  an existing feature type to use as a template, or {@code null} if none.
-     * @param factory   the factory to use for creating names, or {@code null} for the default factory.
-     * @param locale    the locale to use for formatting error messages, or {@code null} for the default locale.
-     */
-    public FeatureTypeBuilder(final FeatureType template, NameFactory factory, final Locale locale) {
-        super(template, locale);
-        if (factory == null) {
-            factory = DefaultFactories.forBuildin(NameFactory.class);
-        }
-        nameFactory = factory;
-        properties  = new ArrayList<>();
-        superTypes  = new ArrayList<>();
-        idDelimiter = ":";
-        defaultMinimumOccurs = 1;
-        defaultMaximumOccurs = 1;
-        if (template != null) {
-            feature    = template;
-            isAbstract = template.isAbstract();
-            superTypes.addAll(template.getSuperTypes());
-            for (final PropertyType p : template.getProperties(false)) {
-                final Property builder;
-                if (p instanceof AttributeType<?>) {
-                    builder = new Attribute<>(this, (AttributeType<?>) p);
-                } else if (p instanceof FeatureAssociationRole) {
-                    builder = new Association(this, (FeatureAssociationRole) p);
-                } else {
-                    continue;           // Skip unknown types.
-                }
-                properties.add(builder);
-            }
-        }
-    }
-
-    /**
-     * If the {@code FeatureType} created by the last call to {@link #build()} has been cached,
-     * clears that cache. This method must be invoked every time that a setter method is invoked.
-     */
-    @Override
-    final void clearCache() {
-        feature = null;
-    }
-
-    /**
-     * Returns {@code true} if the feature type to create will act as an abstract super-type.
-     * Abstract types can not be {@linkplain DefaultFeatureType#newInstance() instantiated}.
-     *
-     * @return {@code true} if the feature type to create will act as an abstract super-type.
-     *
-     * @see DefaultFeatureType#isAbstract()
-     */
-    public boolean isAbstract() {
-        return isAbstract;
-    }
-
-    /**
-     * Sets whether the feature type to create will be abstract.
-     * If this method is not invoked, then the default value is {@code false}.
-     *
-     * @param  isAbstract whether the feature type will be abstract.
-     * @return {@code this} for allowing method calls chaining.
-     */
-    public FeatureTypeBuilder setAbstract(final boolean isAbstract) {
-        if (this.isAbstract != isAbstract) {
-            this.isAbstract  = isAbstract;
-            clearCache();
-        }
-        return this;
-    }
-
-    /**
-     * Returns the direct parents of the feature type to create.
-     *
-     * @return the parents of the feature type to create, or an empty array if none.
-     *
-     * @see DefaultFeatureType#getSuperTypes()
-     */
-    public FeatureType[] getSuperTypes() {
-        return superTypes.toArray(new FeatureType[superTypes.size()]);
-    }
-
-    /**
-     * Sets the parent types (or super-type) from which to inherit properties.
-     * If this method is not invoked, then the default value is to have no parent.
+     * <p>If this method is not invoked, then the default values are the cardinality specified by the last call
+     * to {@link FeatureTypeBuilder#setDefaultCardinality(int, int)} at the time this instance has been created.
+     * If the later method has not been invoked, then the default cardinality is [1 … 1].</p>
      *
-     * @param  parents  the parent types from which to inherit properties, or an empty array if none.
+     * @param  minimumOccurs  new minimum number of property values.
+     * @param  maximumOccurs  new maximum number of property values.
      * @return {@code this} for allowing method calls chaining.
      */
-    public FeatureTypeBuilder setSuperTypes(final FeatureType... parents) {
-        ensureNonNull("parents", parents);
-        final List<FeatureType> asList = Arrays.asList(parents);
-        if (!superTypes.equals(asList)) {
-            superTypes.clear();
-            superTypes.addAll(asList);
+    @SuppressWarnings("unchecked")
+    public PropertyTypeBuilder setCardinality(final int minimumOccurs, final int maximumOccurs) {
+        if (this.minimumOccurs != minimumOccurs || this.maximumOccurs != maximumOccurs) {
+            if (minimumOccurs < 0 || maximumOccurs < minimumOccurs) {
+                throw new IllegalArgumentException(errors().getString(Errors.Keys.IllegalRange_2, minimumOccurs, maximumOccurs));
+            }
+            this.minimumOccurs = minimumOccurs;
+            this.maximumOccurs = maximumOccurs;
             clearCache();
         }
         return this;
     }
 
     /**
-     * Sets the {@code FeatureType} name as a generic name.
-     * If another name was defined before this method call, that previous value will be discarded.
-     *
-     * <div class="note"><b>Note for subclasses:</b>
-     * all {@code setName(…)} convenience methods in this builder delegate to this method.
-     * Consequently this method can be used as a central place where to control the creation of all names.</div>
-     *
-     * @return {@code this} for allowing method calls chaining.
-     */
-    @Override
-    public FeatureTypeBuilder setName(final GenericName name) {
-        super.setName(name);
-        return this;
-    }
-
-    /**
-     * Sets the {@code FeatureType} name as a simple string with the default scope.
-     * The default scope is the value specified by the last call to {@link #setDefaultScope(String)}.
-     * The name will be a {@linkplain org.apache.sis.util.iso.DefaultLocalName local name} if no default scope
-     * has been specified, or a {@linkplain org.apache.sis.util.iso.DefaultScopedName scoped name} otherwise.
-     *
-     * <p>This convenience method creates a {@link GenericName} instance,
-     * then delegates to {@link #setName(GenericName)}.</p>
-     *
-     * @return {@code this} for allowing method calls chaining.
+     * Returns {@code true} if {@link AttributeRole#IDENTIFIER_COMPONENT} has been associated to this property.
      */
-    @Override
-    public FeatureTypeBuilder setName(final String localPart) {
-        super.setName(localPart);
-        return this;
+    boolean isIdentifier() {
+        return false;
     }
 
     /**
-     * Sets the {@code FeatureType} name as a string in the given scope.
-     * The name will be a {@linkplain org.apache.sis.util.iso.DefaultLocalName local name} if the given scope is
-     * {@code null} or empty, or a {@linkplain org.apache.sis.util.iso.DefaultScopedName scoped name} otherwise.
-     * If a {@linkplain #setDefaultScope(String) default scope} has been specified, then the
-     * {@code scope} argument overrides it.
-     *
-     * <p>This convenience method creates a {@link GenericName} instance,
-     * then delegates to {@link #setName(GenericName)}.</p>
-     *
-     * @return {@code this} for allowing method calls chaining.
+     * Delegates the creation of a new name to the enclosing builder.
      */
     @Override
-    public FeatureTypeBuilder setName(final String scope, final String localPart) {
-        super.setName(scope, localPart);
-        return this;
+    final GenericName name(final String scope, final String localPart) {
+        return owner.name(scope, localPart);
     }
 
     /**
-     * Invoked by {@link FeatureElementBuilder} for creating new {@code LocalName} or {@code GenericName} instances.
+     * If the {@code PropertyType} created by the last call to {@link #build()} has been cached,
+     * clears that cache. This method must be invoked every time that a setter method is invoked.
      */
     @Override
-    final GenericName name(String scope, final String localPart) {
-        if (scope == null) {
-            scope = getDefaultScope();
-        }
-        if (scope == null || scope.isEmpty()) {
-            return nameFactory.createLocalName(null, localPart);
-        } else {
-            return nameFactory.createGenericName(null, scope, localPart);
-        }
-    }
-
-    /**
-     * Returns the scope of the names created by {@code setName(String)} method calls.
-     *
-     * @return the scope to use by default when {@link #setName(String)} is invoked.
-     */
-    public String getDefaultScope() {
-        return defaultScope;
-    }
-
-    /**
-     * Sets the scope of the names created by {@code setName(String)} method calls.
-     *
-     * @param  scope  the new default scope, or {@code null} if none.
-     * @return {@code this} for allowing method calls chaining.
-     */
-    public FeatureTypeBuilder setDefaultScope(final String scope) {
-        defaultScope = scope;
-        // No need to clear the cache because this change affects
-        // only the next names to be created, not the existing ones.
-        return this;
-    }
-
-    /**
-     * Sets the default minimum and maximum number of property values.
-     * Those defaults will applied to newly created attributes or associations,
-     * for example in next calls to {@link #addAttribute(Class)}.
-     *
-     * <p>If this method is not invoked, then the default cardinality is [1 … 1].</p>
-     *
-     * @param  minimumOccurs  new default minimum number of property values.
-     * @param  maximumOccurs  new default maximum number of property values.
-     * @return {@code this} for allowing method calls chaining.
-     *
-     * @see Attribute#setCardinality(int, int)
-     */
-    public FeatureTypeBuilder setDefaultCardinality(final int minimumOccurs, final int maximumOccurs) {
-        if (minimumOccurs < 0 || maximumOccurs < minimumOccurs) {
-            throw new IllegalArgumentException(errors().getString(Errors.Keys.IllegalRange_2, minimumOccurs, maximumOccurs));
-        }
-        defaultMinimumOccurs = minimumOccurs;
-        defaultMaximumOccurs = maximumOccurs;
-        // No need to clear the cache because this change affects only
-        // the next properties to be created, not the existing ones.
-        return this;
-    }
-
-    /**
-     * Sets the prefix, suffix and delimiter to use when formatting a compound identifier made of two or more attributes.
-     * The delimiter will be used only if at least two attributes have the {@linkplain Attribute.Role#IDENTIFIER_COMPONENT
-     * identifier component role}.
-     *
-     * <p>If this method is not invoked, then the default values are the {@code ":"} delimiter and no prefix or suffix.</p>
-     *
-     * @param  delimiter  the characters to use as delimiter between each single property value.
-     * @param  prefix     characters to use at the beginning of the concatenated string, or {@code null} if none.
-     * @param  suffix     characters to use at the end of the concatenated string, or {@code null} if none.
-     * @return {@code this} for allowing method calls chaining.
-     *
-     * @see Attribute.Role#IDENTIFIER_COMPONENT
-     * @see FeatureOperations#compound(Map, String, String, String, PropertyType...)
-     */
-    public FeatureTypeBuilder setIdentifierDelimiters(final String delimiter, final String prefix, final String suffix) {
-        ensureNonEmpty("delimiter", delimiter);
-        if (!delimiter.equals(idDelimiter) || !Objects.equals(prefix, idPrefix) || !Objects.equals(suffix, idSuffix)) {
-            idDelimiter = delimiter;
-            idPrefix    = prefix;
-            idSuffix    = suffix;
-            clearCache();
-        }
-        return this;
+    final void clearCache() {
+        property = null;
+        owner.clearCache();
     }
 
     /**
-     * Creates a new {@code AttributeType} builder for values of the given class.
-     * The default attribute name is the name of the given type, but callers should invoke one
-     * of the {@code Attribute.setName(…)} methods on the returned instance with a better name.
-     *
-     * <p>Usage example:</p>
-     * {@preformat java
-     *     builder.addAttribute(String.class).setName("City").setDefaultValue("Metropolis");
-     * }
-     *
-     * The value class can not be {@code Feature.class} since features shall be handled
-     * as {@linkplain #addAssociation(FeatureType) associations} instead than attributes.
-     *
-     * @param  <V>  the compile-time value of {@code valueClass} argument.
-     * @param  valueClass  the class of attribute values (can not be {@code Feature.class}).
-     * @return a builder for an {@code AttributeType}.
+     * Returns the property type from the current setting.
+     * This method may return an existing property if it was already created.
      */
-    public <V> Attribute<V> addAttribute(final Class<V> valueClass) {
-        ensureNonNull("valueClass", valueClass);
-        if (Feature.class.isAssignableFrom(valueClass)) {
-            // We disallow Feature.class because that type shall be handled as association instead than attribute.
-            throw new IllegalArgumentException(errors().getString(Errors.Keys.IllegalArgumentValue_2, "valueClass", valueClass));
+    final PropertyType build() {
+        if (property == null) {
+            property = create();
         }
-        final Attribute<V> property = new Attribute<>(this, valueClass);
-        properties.add(property);
-        clearCache();
-        return property;
-    }
-
-    /**
-     * Creates a new {@code AttributeType} builder initialized to the same characteristics than the given template.
-     *
-     * @param  <V>       the compile-time type of values in the {@code template} argument.
-     * @param  template  an existing attribute type to use as a template.
-     * @return a builder for an {@code AttributeType}, initialized with the values of the given template.
-     */
-    public <V> Attribute<V> addAttribute(final AttributeType<V> template) {
-        ensureNonNull("template", template);
-        final Attribute<V> property = new Attribute<>(this, template);
-        properties.add(property);
-        clearCache();
         return property;
     }
 
     /**
-     * Creates a new {@code FeatureAssociationRole} builder for features of the given type.
-     * The default association name is the name of the given type, but callers should invoke one
-     * of the {@code Association.setName(…)} methods on the returned instance with a better name.
-     *
-     * @param  type  the type of feature values.
-     * @return a builder for a {@code FeatureAssociationRole}.
-     */
-    public Association addAssociation(final FeatureType type) {
-        ensureNonNull("type", type);
-        final Association property = new Association(this, type, type.getName());
-        properties.add(property);
-        clearCache();
-        return property;
-    }
-
-    /**
-     * Creates a new {@code FeatureAssociationRole} builder for features of a type of the given name.
-     * This method can be invoked as an alternative to {@link #addAssociation(FeatureType)} when the
-     * {@code FeatureType} instance is not yet available because of cyclic dependency.
-     *
-     * @param  type  the name of the type of feature values.
-     * @return a builder for a {@code FeatureAssociationRole}.
-     */
-    public Association addAssociation(final GenericName type) {
-        ensureNonNull("type", type);
-        final Association property = new Association(this, null, type);
-        properties.add(property);
-        clearCache();
-        return property;
-    }
-
-    /**
-     * Creates a new {@code FeatureAssociationRole} builder initialized to the same characteristics
-     * than the given template.
-     *
-     * @param  template  an existing feature association to use as a template.
-     * @return a builder for an {@code FeatureAssociationRole}, initialized with the values of the given template.
-     */
-    public Association addAssociation(final FeatureAssociationRole template) {
-        ensureNonNull("template", template);
-        final Association property = new Association(this, template);
-        properties.add(property);
-        clearCache();
-        return property;
-    }
-
-
-
-
-    /**
-     * Describes one property of the {@code FeatureType} to be built by the enclosing {@code FeatureTypeBuilder}.
-     * A different instance of {@code Property} exists for each property to describe. Those instances are created by:
-     *
-     * <ul>
-     *   <li>{@link FeatureTypeBuilder#addAttribute(Class)}</li>
-     *   <li>{@link FeatureTypeBuilder#addAssociation(FeatureType)}</li>
-     *   <li>{@link FeatureTypeBuilder#addAssociation(GenericName)}</li>
-     * </ul>
-     */
-    public static abstract class Property extends FeatureElementBuilder {
-        /**
-         * The feature type builder instance that created this {@code Property} builder.
-         *
-         * <div class="note">We could replace this reference by a non-static {@code Property} class.
-         * But we do not for consistency with {@link Characteristic} and for allowing the inner
-         * {@code Attribute.Role} enumeration.</div>
-         */
-        final FeatureTypeBuilder owner;
-
-        /**
-         * The minimum number of property values.
-         * The default value is 1, unless otherwise specified by {@link #setDefaultCardinality(int, int)}.
-         *
-         * @see #setCardinality(int, int)
-         */
-        int minimumOccurs;
-
-        /**
-         * The maximum number of property values.
-         * The default value is 1, unless otherwise specified by {@link #setDefaultCardinality(int, int)}.
-         *
-         * @see #setCardinality(int, int)
-         */
-        int maximumOccurs;
-
-        /**
-         * The attribute or association created by this builder, or {@code null} if not yet created.
-         * This field must be cleared every time that a setter method is invoked on this builder.
-         */
-        private transient PropertyType property;
-
-        /**
-         * Creates a new {@code PropertyType} builder initialized to the values of an existing property.
-         *
-         * @param owner     the builder of the {@code FeatureType} for which to add this property.
-         * @param template  an existing property to use as a template, or {@code null} if none.
-         */
-        Property(final FeatureTypeBuilder owner, final PropertyType template) {
-            super(template, owner.getLocale());
-            this.owner    = owner;
-            minimumOccurs = owner.defaultMinimumOccurs;
-            maximumOccurs = owner.defaultMaximumOccurs;
-            property      = template;
-        }
-
-        /**
-         * Sets the minimum and maximum number of property values. Those numbers must be equal or greater than zero.
-         *
-         * <p>If this method is not invoked, then the default values are the cardinality specified by the last call
-         * to {@link FeatureTypeBuilder#setDefaultCardinality(int, int)} at the time this instance has been created.
-         * If the later method has not been invoked, then the default cardinality is [1 … 1].</p>
-         *
-         * @param  minimumOccurs  new minimum number of property values.
-         * @param  maximumOccurs  new maximum number of property values.
-         * @return {@code this} for allowing method calls chaining.
-         */
-        @SuppressWarnings("unchecked")
-        public Property setCardinality(final int minimumOccurs, final int maximumOccurs) {
-            if (this.minimumOccurs != minimumOccurs || this.maximumOccurs != maximumOccurs) {
-                if (minimumOccurs < 0 || maximumOccurs < minimumOccurs) {
-                    throw new IllegalArgumentException(errors().getString(Errors.Keys.IllegalRange_2, minimumOccurs, maximumOccurs));
-                }
-                this.minimumOccurs = minimumOccurs;
-                this.maximumOccurs = maximumOccurs;
-                clearCache();
-            }
-            return this;
-        }
-
-        /**
-         * Returns {@code true} if {@link Attribute.Role#IDENTIFIER_COMPONENT} has been associated to this property.
-         */
-        boolean isIdentifier() {
-            return false;
-        }
-
-        /**
-         * Delegates the creation of a new name to the enclosing builder.
-         */
-        @Override
-        final GenericName name(final String scope, final String localPart) {
-            return owner.name(scope, localPart);
-        }
-
-        /**
-         * If the {@code PropertyType} created by the last call to {@link #build()} has been cached,
-         * clears that cache. This method must be invoked every time that a setter method is invoked.
-         */
-        @Override
-        final void clearCache() {
-            property = null;
-            owner.clearCache();
-        }
-
-        /**
-         * Returns the property type from the current setting.
-         * This method may return an existing property if it was already created.
-         */
-        final PropertyType build() {
-            if (property == null) {
-                property = create();
-            }
-            return property;
-        }
-
-        /**
-         * Creates a new property type from the current setting.
-         */
-        abstract PropertyType create();
-    }
-
-
-
-
-    /**
-     * Describes one association from the {@code FeatureType} to be built by the enclosing {@code FeatureTypeBuilder}
-     * to another {@code FeatureType}. A different instance of {@code Association} exists for each feature association
-     * to describe. Those instances are created preferably by {@link FeatureTypeBuilder#addAssociation(FeatureType)},
-     * or in case of cyclic reference by {@link FeatureTypeBuilder#addAssociation(GenericName)}.
-     *
-     * @see FeatureTypeBuilder#addAssociation(FeatureType)
-     * @see FeatureTypeBuilder#addAssociation(GenericName)
-     */
-    public static final class Association extends Property {
-        /**
-         * The target feature type, or {@code null} if unknown.
-         */
-        private final FeatureType type;
-
-        /**
-         * Name of the target feature type (never null).
-         */
-        private final GenericName typeName;
-
-        /**
-         * Creates a new {@code AssociationRole} builder for values of the given type.
-         * The {@code type} argument can be null if unknown, but {@code typeName} is mandatory.
-         *
-         * @param owner  the builder of the {@code FeatureType} for which to add this property.
-         */
-        Association(final FeatureTypeBuilder owner, final FeatureType type, final GenericName typeName) {
-            super(owner, null);
-            this.type     = type;
-            this.typeName = typeName;
-        }
-
-        /**
-         * Creates a new {@code FeatureAssociationRole} builder initialized to the values of an existing association.
-         *
-         * @param owner  the builder of the {@code FeatureType} for which to add this property.
-         */
-        Association(final FeatureTypeBuilder owner, final FeatureAssociationRole template) {
-            super(owner, template);
-            minimumOccurs = template.getMinimumOccurs();
-            maximumOccurs = template.getMaximumOccurs();
-            type          = template.getValueType();
-            typeName      = type.getName();
-        }
-
-        /**
-         * Appends a text inside the value returned by {@link #toString()}, before the closing bracket.
-         */
-        @Override
-        final void toStringInternal(final StringBuilder buffer) {
-            buffer.append(" → ").append(typeName);
-        }
-
-        /**
-         * Returns a default name to use if the user did not specified a name. The first letter will be changed to
-         * lower case (unless the name looks like an acronym) for compliance with Java convention on property names.
-         */
-        @Override
-        final String getDefaultName() {
-            return typeName.tip().toString();
-        }
-
-        /**
-         * Sets the {@code FeatureAssociationRole} name as a generic name.
-         * If another name was defined before this method call, that previous value will be discarded.
-         *
-         * @return {@code this} for allowing method calls chaining.
-         */
-        @Override
-        public Association setName(final GenericName name) {
-            super.setName(name);
-            return this;
-        }
-
-        /**
-         * Sets the {@code FeatureAssociationRole} name as a simple string with the default scope.
-         * The default scope is the value specified by the last call to
-         * {@link FeatureTypeBuilder#setDefaultScope(String)}.
-         * The name will be a {@linkplain org.apache.sis.util.iso.DefaultLocalName local name} if no default scope
-         * has been specified, or a {@linkplain org.apache.sis.util.iso.DefaultScopedName scoped name} otherwise.
-         *
-         * @return {@code this} for allowing method calls chaining.
-         */
-        @Override
-        public Association setName(final String localPart) {
-            super.setName(localPart);
-            return this;
-        }
-
-        /**
-         * Sets the {@code FeatureAssociationRole} name as a string in the given scope.
-         * The name will be a {@linkplain org.apache.sis.util.iso.DefaultLocalName local name} if the given scope is
-         * {@code null} or empty, or a {@linkplain org.apache.sis.util.iso.DefaultScopedName scoped name} otherwise.
-         * If a {@linkplain FeatureTypeBuilder#setDefaultScope(String) default scope} has been specified, then the
-         * {@code scope} argument overrides it.
-         *
-         * @return {@code this} for allowing method calls chaining.
-         */
-        @Override
-        public Association setName(final String scope, final String localPart) {
-            super.setName(scope, localPart);
-            return this;
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public Association setDefinition(final CharSequence definition) {
-            super.setDefinition(definition);
-            return this;
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public Association setDesignation(final CharSequence designation) {
-            super.setDesignation(designation);
-            return this;
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public Association setDescription(final CharSequence description) {
-            super.setDescription(description);
-            return this;
-        }
-
-        /**
-         * Creates a new property type from the current setting.
-         */
-        @Override
-        final PropertyType create() {
-            if (type != null) {
-                return new DefaultAssociationRole(identification(), type, minimumOccurs, maximumOccurs);
-            } else {
-                return new DefaultAssociationRole(identification(), typeName, minimumOccurs, maximumOccurs);
-            }
-        }
-    }
-
-
-
-
-    /**
-     * Describes one attribute of the {@code FeatureType} to be built by the enclosing {@code FeatureTypeBuilder}.
-     * A different instance of {@code Attribute} exists for each feature attribute to describe.
-     * Those instances are created by {@link FeatureTypeBuilder#addAttribute(Class)}.
-     *
-     * @param <V> the class of property values.
-     *
-     * @see FeatureTypeBuilder#addAttribute(Class)
-     */
-    public static final class Attribute<V> extends Property {
-        /**
-         * The class of property values. Can not be changed after construction
-         * because this value determines the parameterized type {@code <V>}.
-         */
-        private final Class<V> valueClass;
-
-        /**
-         * The default value for the property, or {@code null} if none.
-         */
-        private V defaultValue;
-
-        /**
-         * Whether this attribute will be used in a {@linkplain FeatureOperations#compound compound key} named
-         * {@code "@identifier"}. If only one attribute has this flag and {@link FeatureTypeBuilder#idPrefix} and
-         * {@code isSuffix} are null, then {@code "@identifier"} will be a {@linkplain FeatureOperations#link link}
-         * to {@code idAttributes[0]}.
-         *
-         * @see #addRole(Role)
-         */
-        private boolean isIdentifier;
-
-        /**
-         * Builders for the characteristics associated to the attribute.
-         */
-        private final List<Characteristic<?>> characteristics = new ArrayList<>();
-
-        /**
-         * Creates a new {@code AttributeType} builder for values of the given class.
-         *
-         * @param owner      the builder of the {@code FeatureType} for which to add this property.
-         * @param valueClass the class of property values.
-         */
-        Attribute(final FeatureTypeBuilder owner, final Class<V> valueClass) {
-            super(owner, null);
-            this.valueClass = valueClass;
-        }
-
-        /**
-         * Creates a new {@code AttributeType} builder initialized to the values of an existing attribute.
-         *
-         * @param owner  the builder of the {@code FeatureType} for which to add this property.
-         */
-        Attribute(final FeatureTypeBuilder owner, final AttributeType<V> template) {
-            super(owner, template);
-            minimumOccurs = template.getMinimumOccurs();
-            maximumOccurs = template.getMaximumOccurs();
-            valueClass    = template.getValueClass();
-            defaultValue  = template.getDefaultValue();
-            for (final AttributeType<?> c : template.characteristics().values()) {
-                characteristics.add(new Characteristic<>(this, c));
-            }
-        }
-
-        /**
-         * Returns a default name to use if the user did not specified a name. The first letter will be changed to
-         * lower case (unless the name looks like an acronym) for compliance with Java convention on property names.
-         */
-        @Override
-        final String getDefaultName() {
-            return Classes.getShortName(valueClass);
-        }
-
-        /**
-         * Sets the {@code AttributeType} name as a generic name.
-         * If another name was defined before this method call, that previous value will be discarded.
-         *
-         * @return {@code this} for allowing method calls chaining.
-         */
-        @Override
-        public Attribute<V> setName(final GenericName name) {
-            super.setName(name);
-            return this;
-        }
-
-        /**
-         * Sets the {@code AttributeType} name as a simple string with the default scope.
-         * The default scope is the value specified by the last call to
-         * {@link FeatureTypeBuilder#setDefaultScope(String)}.
-         * The name will be a {@linkplain org.apache.sis.util.iso.DefaultLocalName local name} if no default scope
-         * has been specified, or a {@linkplain org.apache.sis.util.iso.DefaultScopedName scoped name} otherwise.
-         *
-         * @return {@code this} for allowing method calls chaining.
-         */
-        @Override
-        public Attribute<V> setName(final String localPart) {
-            super.setName(localPart);
-            return this;
-        }
-
-        /**
-         * Sets the {@code AttributeType} name as a string in the given scope.
-         * The name will be a {@linkplain org.apache.sis.util.iso.DefaultLocalName local name} if the given scope is
-         * {@code null} or empty, or a {@linkplain org.apache.sis.util.iso.DefaultScopedName scoped name} otherwise.
-         * If a {@linkplain FeatureTypeBuilder#setDefaultScope(String) default scope} has been specified, then the
-         * {@code scope} argument overrides it.
-         *
-         * @return {@code this} for allowing method calls chaining.
-         */
-        @Override
-        public Attribute<V> setName(final String scope, final String localPart) {
-            super.setName(scope, localPart);
-            return this;
-        }
-
-        /**
-         * Sets the default value for the property.
-         *
-         * @param  value  default property value, or {@code null} if none.
-         * @return {@code this} for allowing method calls chaining.
-         */
-        public Attribute<V> setDefaultValue(final V value) {
-            if (!Objects.equals(defaultValue, value)) {
-                defaultValue = value;
-                clearCache();
-            }
-            return this;
-        }
-
-        /**
-         * Sets an enumeration of valid values for this attribute.
-         *
-         * <p>This is a convenience method for {@link #addCharacteristic(Class)} with a value
-         * of type {@link Set} and a conventional name.</p>
-         *
-         * @param  values valid values.
-         * @return {@code this} for allowing method calls chaining.
-         * @throws UnsupportedOperationException if this property does not support characteristics.
-         *
-         * @see AttributeConvention#VALID_VALUES_CHARACTERISTIC
-         */
-        @SafeVarargs
-        public final Attribute<V> setValidValues(final V... values) {
-            return setCharacteristic(AttributeConvention.VALID_VALUES_CHARACTERISTIC,
-                    Set.class, CollectionsExt.immutableSet(false, values));
-        }
-
-        /**
-         * Sets the maximal length that characterizes the {@link CharSequence} values of this attribute.
-         * While this characteristic can be applied to any kind of attribute, it is meaningful only with
-         * character sequences.
-         *
-         * <p>This is a convenience method for {@link #addCharacteristic(Class)} with a value
-         * of type {@link Integer} and a conventional name.</p>
-         *
-         * @param  length  maximal length of {@link CharSequence} attribute values, or {@code null}.
-         * @return {@code this} for allowing method calls chaining.
-         * @throws UnsupportedOperationException if this property does not support length characteristics.
-         *
-         * @see AttributeConvention#MAXIMAL_LENGTH_CHARACTERISTIC
-         */
-        public Attribute<V> setMaximalLengthCharacteristic(final Integer length) {
-            return setCharacteristic(AttributeConvention.MAXIMAL_LENGTH_CHARACTERISTIC, Integer.class, length);
-        }
-
-        /**
-         * Sets the coordinate reference system that characterizes the values of this attribute.
-         * While this characteristic can be applied to any kind of attribute, it is meaningful
-         * only with georeferenced values like geometries or coverages.
-         *
-         * <p>This is a convenience method for {@link #addCharacteristic(Class)} with a value
-         * of type {@link CoordinateReferenceSystem} and a conventional name.</p>
-         *
-         * @param  crs  coordinate reference system associated to attribute values, or {@code null}.
-         * @return {@code this} for allowing method calls chaining.
-         * @throws UnsupportedOperationException if this property does not support CRS characteristics.
-         *
-         * @see AttributeConvention#CRS_CHARACTERISTIC
-         */
-        public Attribute<V> setCRSCharacteristic(final CoordinateReferenceSystem crs) {
-            return setCharacteristic(AttributeConvention.CRS_CHARACTERISTIC, CoordinateReferenceSystem.class, crs);
-        }
-
-        /**
-         * Implementation of all setter methods for characteristics.
-         *
-         * @throws UnsupportedOperationException if this property does not support characteristics.
-         */
-        private <C> Attribute<V> setCharacteristic(final GenericName name, final Class<C> type, final C value) {
-            for (final Characteristic<?> characteristic : characteristics) {
-                if (name.equals(characteristic.getName())) {
-                    characteristic.set(value);
-                    return this;
-                }
-            }
-            addCharacteristic(type).setDefaultValue(value).setName(name);
-            return this;
-        }
-
-        /**
-         * Adds another attribute type that describes this attribute type.
-         * See <cite>"Attribute characterization"</cite> in {@link DefaultAttributeType} Javadoc for more information.
-         *
-         * <p>Usage example:</p>
-         * {@preformat java
-         *     attribute.addCharacteristic(Unit.class).setName("Unit of measurement").setDefaultValue(SI.CELSIUS);
-         * }
-         *
-         * The default characteristic name is the name of the given type, but callers should invoke one
-         * of the {@code Characteristic.setName(…)} methods on the returned instance with a better name.
-         *
-         * @param  <C>   the compile-time type of {@code type} argument.
-         * @param  type  the class of characteristic values.
-         * @return a builder for a characteristic of this attribute.
-         */
-        public <C> Characteristic<C> addCharacteristic(final Class<C> type) {
-            if (valueClass == Feature.class) {
-                throw new UnsupportedOperationException(errors().getString(Errors.Keys.IllegalOperationForValueClass_1, valueClass));
-            }
-            ensureNonNull("type", type);
-            final Characteristic<C> characteristic = new Characteristic<>(this, type);
-            characteristics.add(characteristic);
-            clearCache();
-            return characteristic;
-        }
-
-        /**
-         * Adds another attribute type that describes this attribute type, using an existing one as a template.
-         * See <cite>"Attribute characterization"</cite> in {@link DefaultAttributeType} Javadoc for more information.
-         *
-         * @param  <C>       the compile-time type of values in the {@code template} argument.
-         * @param  template  an existing attribute type to use as a template.
-         * @return a builder for a characteristic of this attribute, initialized with the values of the given template.
-         */
-        public <C> Characteristic<C> addCharacteristic(final AttributeType<C> template) {
-            ensureNonNull("template", template);
-            final Characteristic<C> characteristic = new Characteristic<>(this, template);
-            characteristics.add(characteristic);
-            clearCache();
-            return characteristic;
-        }
-
-        /**
-         * Roles that can be associated to some attributes for instructing {@code FeatureTypeBuilder}
-         * how to generate pre-defined operations. Those pre-defined operations are:
-         *
-         * <ul>
-         *   <li>A {@linkplain FeatureOperations#compound compound operation} for generating a unique identifier
-         *       from an arbitrary amount of attribute values.</li>
-         *   <li>A {@linkplain FeatureOperations#link link operation} for referencing a geometry to be used as the
-         *       <em>default</em> geometry.</li>
-         *   <li>An {@linkplain FeatureOperations#envelope operation} for computing the bounding box of all geometries
-         *       found in the feature. This operation is automatically added if the feature contains a default geometry.</li>
-         * </ul>
-         *
-         * This enumeration allows user code to specify which feature attribute to use for creating those operations.
-         *
-         * @see Attribute#addRole(Role)
-         */
-        public static enum Role {
-            /**
-             * Attribute value will be part of a unique identifier for the feature instance.
-             * An arbitrary amount of attributes can be flagged as identifier components:
-             *
-             * <ul>
-             *   <li>If no attribute has this role, then no attribute is marked as feature identifier.</li>
-             *   <li>If exactly one attribute has this role, then a synthetic attribute named {@code "@identifier"}
-             *       will be created as a {@linkplain FeatureOperations#link link} to the flagged attribute.</li>
-             *   <li>If more than one attribute have this role, then a synthetic attribute named {@code "@identifier"}
-             *       will be created as a {@linkplain FeatureOperations#compound compound key} made of all flagged
-             *       attributes. The separator character can be modified by a call to
-             *       {@link FeatureTypeBuilder#setIdentifierDelimiters(String, String, String)}</li>
-             * </ul>
-             *
-             * @see FeatureTypeBuilder#setIdentifierDelimiters(String, String, String)
-             */
-            IDENTIFIER_COMPONENT,
-
-            /**
-             * Attribute value will be flagged as the <em>default</em> geometry.
-             * Feature can have an arbitrary amount of geometry attributes,
-             * but only one can be flagged as the default geometry.
-             */
-            DEFAULT_GEOMETRY
-        }
-
-        /**
-         * Flags this attribute as an input of one of the pre-defined operations managed by {@code FeatureTypeBuilder}.
-         *
-         * @param role the role to add to this attribute (shall not be null).
-         */
-        public void addRole(final Role role) {
-            ensureNonNull("role", role);
-            switch (role) {
-                case IDENTIFIER_COMPONENT: {
-                    if (!isIdentifier) {
-                        isIdentifier = true;
-                        owner.identifierCount++;
-                        owner.clearCache();         // The change does not impact this attribute itself.
-                    }
-                    break;
-                }
-                case DEFAULT_GEOMETRY: {
-                    if (owner.defaultGeometry != this) {
-                        if (!Geometries.isKnownType(valueClass)) {
-                            throw new IllegalStateException(errors().getString(Errors.Keys.UnsupportedImplementation_1, valueClass));
-                        }
-                        if (owner.defaultGeometry != null) {
-                            throw new IllegalStateException(errors().getString(Errors.Keys.PropertyAlreadyExists_2,
-                                    owner.getDisplayName(), AttributeConvention.GEOMETRY_PROPERTY));
-                        }
-                        owner.defaultGeometry = this;
-                        owner.clearCache();         // The change does not impact this attribute itself.
-                    }
-                    break;
-                }
-            }
-        }
-
-        /**
-         * Returns {@code true} if {@link Role#IDENTIFIER_COMPONENT} has been associated to this attribute.
-         */
-        @Override
-        boolean isIdentifier() {
-            return isIdentifier;
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public Attribute<V> setDefinition(final CharSequence definition) {
-            super.setDefinition(definition);
-            return this;
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public Attribute<V> setDesignation(final CharSequence designation) {
-            super.setDesignation(designation);
-            return this;
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public Attribute<V> setDescription(final CharSequence description) {
-            super.setDescription(description);
-            return this;
-        }
-
-        /**
-         * Appends a text inside the value returned by {@link #toString()}, before the closing bracket.
-         */
-        @Override
-        final void toStringInternal(final StringBuilder buffer) {
-            buffer.append(" : ").append(Classes.getShortName(valueClass));
-        }
-
-        /**
-         * Creates a new property type from the current setting.
-         */
-        @Override
-        final PropertyType create() {
-            final AttributeType<?>[] chrts = new AttributeType<?>[characteristics.size()];
-            for (int i=0; i<chrts.length; i++) {
-                chrts[i] = characteristics.get(i).build();
-            }
-            return new DefaultAttributeType<>(identification(), valueClass, minimumOccurs, maximumOccurs, defaultValue, chrts);
-        }
-    }
-
-
-
-
-    /**
-     * Describes one characteristic of an {@code AttributeType} to be built by the enclosing {@code FeatureTypeBuilder}.
-     * A different instance of {@code Characteristic} exists for each characteristic to describe.
-     * Those instances are created by:
-     *
-     * <ul>
-     *   <li>{@link Attribute#addCharacteristic(Class)}</li>
-     * </ul>
-     *
-     * @param <V> the class of characteristic values.
+     * Creates a new property type from the current setting.
      */
-    public static final class Characteristic<V> extends FeatureElementBuilder {
-        /**
-         * The attribute type builder instance that created this {@code Characteristic} builder.
-         */
-        private final Attribute<?> owner;
-
-        /**
-         * The class of attribute values. Can not be changed after construction
-         * because this value determines the parameterized type {@code <V>}.
-         */
-        private final Class<V> valueClass;
-
-        /**
-         * The default value for the attribute, or {@code null} if none.
-         */
-        private V defaultValue;
-
-        /**
-         * The characteristic created by this builder, or {@code null} if not yet created.
-         * This field must be cleared every time that a setter method is invoked on this builder.
-         */
-        private transient AttributeType<V> characteristic;
-
-        /**
-         * Creates a new characteristic builder for values of the given class.
-         *
-         * @param owner      the builder of the {@code AttributeType} for which to add this property.
-         * @param valueClass the class of characteristic values.
-         */
-        Characteristic(final Attribute<?> owner, final Class<V> valueClass) {
-            super(null, owner.getLocale());
-            this.owner = owner;
-            this.valueClass = valueClass;
-        }
-
-        /**
-         * Creates a new characteristic builder initialized to the values of an existing attribute.
-         *
-         * @param owner  the builder of the {@code AttributeType} for which to add this property.
-         */
-        Characteristic(final Attribute<?> owner, final AttributeType<V> template) {
-            super(template, owner.getLocale());
-            this.owner     = owner;
-            valueClass     = template.getValueClass();
-            defaultValue   = template.getDefaultValue();
-            characteristic = template;
-        }
-
-        /**
-         * If the {@code AttributeType<V>} created by the last call to {@link #build()} has been cached,
-         * clears that cache. This method must be invoked every time that a setter method is invoked.
-         */
-        @Override
-        final void clearCache() {
-            characteristic = null;
-            owner.clearCache();
-        }
-
-        /**
-         * Returns a default name to use if the user did not specified a name. The first letter will be changed to
-         * lower case (unless the name looks like an acronym) for compliance with Java convention on property names.
-         */
-        @Override
-        final String getDefaultName() {
-            return Classes.getShortName(valueClass);
-        }
-
-        /**
-         * Sets the characteristic name as a generic name.
-         * If another name was defined before this method call, that previous value will be discarded.
-         *
-         * @return {@code this} for allowing method calls chaining.
-         */
-        @Override
-        public Characteristic<V> setName(final GenericName name) {
-            super.setName(name);
-            return this;
-        }
-
-        /**
-         * Sets the characteristic name as a simple string with the default scope.
-         * The default scope is the value specified by the last call to
-         * {@link FeatureTypeBuilder#setDefaultScope(String)}.
-         * The name will be a {@linkplain org.apache.sis.util.iso.DefaultLocalName local name} if no default scope
-         * has been specified, or a {@linkplain org.apache.sis.util.iso.DefaultScopedName scoped name} otherwise.
-         *
-         * @return {@code this} for allowing method calls chaining.
-         */
-        @Override
-        public Characteristic<V> setName(final String localPart) {
-            super.setName(localPart);
-            return this;
-        }
-
-        /**
-         * Sets the characteristic name as a string in the given scope.
-         * The name will be a {@linkplain org.apache.sis.util.iso.DefaultLocalName local name} if the given scope is
-         * {@code null} or empty, or a {@linkplain org.apache.sis.util.iso.DefaultScopedName scoped name} otherwise.
-         * If a {@linkplain FeatureTypeBuilder#setDefaultScope(String) default scope} has been specified, then the
-         * {@code scope} argument overrides it.
-         *
-         * @return {@code this} for allowing method calls chaining.
-         */
-        @Override
-        public Characteristic<V> setName(final String scope, final String localPart) {
-            super.setName(scope, localPart);
-            return this;
-        }
-
-        /**
-         * Delegates the creation of a new name to the enclosing builder.
-         */
-        @Override
-        final GenericName name(final String scope, final String localPart) {
-            return owner.name(scope, localPart);
-        }
-
-        /**
-         * Sets the default value with check of the value class.
-         */
-        final void set(final Object value) {
-            setDefaultValue(valueClass.cast(value));
-        }
-
-        /**
-         * Sets the default value for the characteristic.
-         *
-         * @param  value  characteristic default value, or {@code null} if none.
-         * @return {@code this} for allowing method calls chaining.
-         */
-        public Characteristic<V> setDefaultValue(final V value) {
-            if (!Objects.equals(defaultValue, value)) {
-                defaultValue = value;
-                clearCache();
-            }
-            return this;
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public Characteristic<V> setDefinition(final CharSequence definition) {
-            super.setDefinition(definition);
-            return this;
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public Characteristic<V> setDesignation(final CharSequence designation) {
-            super.setDesignation(designation);
-            return this;
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public Characteristic<V> setDescription(final CharSequence description) {
-            super.setDescription(description);
-            return this;
-        }
-
-        /**
-         * Creates a new characteristic from the current setting.
-         */
-        final AttributeType<V> build() {
-            if (characteristic == null) {
-                characteristic = new DefaultAttributeType<>(identification(), valueClass, 0, 1, defaultValue);
-            }
-            return characteristic;
-        }
-    }
-
-
-
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public FeatureTypeBuilder setDefinition(final CharSequence definition) {
-        super.setDefinition(definition);
-        return this;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public FeatureTypeBuilder setDesignation(final CharSequence designation) {
-        super.setDesignation(designation);
-        return this;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public FeatureTypeBuilder setDescription(final CharSequence description) {
-        super.setDescription(description);
-        return this;
-    }
-
-    /**
-     * Builds the feature type from the information and properties specified to this builder.
-     * One of the {@code setName(…)} methods must have been invoked before this {@code build()} method (mandatory).
-     * All other methods are optional, but some calls to a {@code add} method are usually needed.
-     *
-     * @return the new feature type.
-     * @throws IllegalStateException if the feature type contains incompatible
-     *         {@linkplain Attribute#setCRSCharacteristic CRS characteristics}.
-     */
-    public FeatureType build() throws IllegalStateException {
-        if (feature == null) {
-            /*
-             * Creates an initial array of property types with up to 3 slots reserved for @identifier, @geometry
-             * and @envelope operations. At first we presume that there is always an identifier.  The identifier
-             * slot will be removed later if there is none.
-             */
-            final int numSpecified = properties.size();     // Number of explicitely specified properties.
-            int numSynthetic;                               // Number of synthetic properties that may be generated.
-            int envelopeIndex = -1;
-            int geometryIndex = -1;
-            final PropertyType[] identifierTypes;
-            if (identifierCount == 0) {
-                numSynthetic    = 0;
-                identifierTypes = null;
-            } else {
-                numSynthetic    = 1;
-                identifierTypes = new PropertyType[identifierCount];
-            }
-            if (defaultGeometry != null) {
-                envelopeIndex = numSynthetic;
-                geometryIndex = numSynthetic + 1;
-                numSynthetic += 2;
-            }
-            final PropertyType[] propertyTypes = new PropertyType[numSynthetic + numSpecified];
-            int propertyCursor = numSynthetic;
-            int identifierCursor = 0;
-            for (int i=0; i<numSpecified; i++) {
-                final Property     builder = properties.get(i);
-                final PropertyType instance = builder.build();
-                propertyTypes[propertyCursor] = instance;
-                /*
-                 * Collect the attributes to use as identifier components while we loop over all properties.
-                 * A NullPointerException or an ArrayIndexOutOfBoundsException in this block would mean that
-                 * identifierCount field has not been updated correctly by an Attribute.addRole(Role) method.
-                 */
-                if (builder.isIdentifier()) {
-                    identifierTypes[identifierCursor++] = instance;
-                }
-                /*
-                 * If there is a default geometry, add a link named "@geometry" to that geometry.
-                 * It may happen that the property created by the user is already named "@geometry",
-                 * in which case we will avoid to duplicate the property.
-                 */
-                if (builder == defaultGeometry) {
-                    if (propertyTypes[geometryIndex] != null) {
-                        // Assuming that there is no bug in our implementation, this error could happen if the user
-                        // has modified this FeatureTypeBuilder in another thread during this build() execution.
-                        throw new CorruptedObjectException();
-                    }
-                    if (AttributeConvention.GEOMETRY_PROPERTY.equals(instance.getName())) {
-                        System.arraycopy(propertyTypes, geometryIndex, propertyTypes, geometryIndex-1, (numSynthetic - geometryIndex) + i);
-                        geometryIndex = -1;
-                        numSynthetic--;
-                        continue;           // Skip the increment of propertyCursor.
-                    }
-                    propertyTypes[geometryIndex] = FeatureOperations.link(name(AttributeConvention.GEOMETRY_PROPERTY), instance);
-                }
-                propertyCursor++;
-            }
-            /*
-             * Create the "envelope" operation only after we created all other properties.
-             * Actually it is okay if the 'propertyTypes' array still contains null elements not needed for envelope calculation
-             * like "@identifier", since FeatureOperations.envelope(…) constructor ignores any property which is not for a value.
-             */
-            if (envelopeIndex >= 0) try {
-                propertyTypes[envelopeIndex] = FeatureOperations.envelope(name(AttributeConvention.ENVELOPE_PROPERTY), null, propertyTypes);
-            } catch (FactoryException e) {
-                throw new IllegalStateException(e);
-            }
-            /*
-             * If a synthetic identifier need to be created, create it now as the first property.
-             * It may happen that the user provided a single identifier component already named
-             * "@identifier", in which case we avoid to duplicate the property.
-             */
-            if (identifierTypes != null) {
-                if (identifierCursor != identifierTypes.length) {
-                    // Assuming that there is no bug in our implementation, this error could happen if the user
-                    // has modified this FeatureTypeBuilder in another thread during this build() execution.
-                    throw new CorruptedObjectException();
-                }
-                if (identifierCursor == 1 && AttributeConvention.IDENTIFIER_PROPERTY.equals(identifierTypes[0].getName())) {
-                    System.arraycopy(propertyTypes, 1, propertyTypes, 0, --propertyCursor);
-                } else {
-                    propertyTypes[0] = FeatureOperations.compound(name(AttributeConvention.IDENTIFIER_PROPERTY),
-                            idDelimiter, idPrefix, idSuffix, identifierTypes);
-                }
-            }
-            feature = new DefaultFeatureType(identification(), isAbstract(),
-                    superTypes.toArray(new FeatureType[superTypes.size()]),
-                    ArraysExt.resize(propertyTypes, propertyCursor));
-        }
-        return feature;
-    }
-
-    /**
-     * Helper method for creating identification info of synthetic attributes.
-     */
-    static Map<String,?> name(final GenericName name) {
-        return Collections.singletonMap(AbstractOperation.NAME_KEY, name);
-    }
-
-    /**
-     * Formats a string representation of this builder for debugging purpose.
-     */
-    @Override
-    final void toStringInternal(final StringBuilder buffer) {
-        if (isAbstract()) {
-            buffer.insert(buffer.indexOf("[") + 1, "abstract ");
-        }
-        String separator = " : ";
-        for (final FeatureType parent : superTypes) {
-            buffer.append(separator).append('“').append(parent.getName()).append('”');
-            separator = ", ";
-        }
-        buffer.append(" {");
-        separator = System.lineSeparator();
-        for (final Property p : properties) {
-            p.toString(buffer.append(separator).append("    ").append(p.getClass().getSimpleName()));
-        }
-        buffer.append(separator).append('}');
-    }
+    abstract PropertyType create();
 }

Added: sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/builder/RemoveOnlyList.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/builder/RemoveOnlyList.java?rev=1752158&view=auto
==============================================================================
--- sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/builder/RemoveOnlyList.java (added)
+++ sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/builder/RemoveOnlyList.java [UTF-8] Mon Jul 11 13:29:44 2016
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.feature.builder;
+
+import java.util.AbstractList;
+import java.util.Iterator;
+import java.util.List;
+
+
+/**
+ * Wraps another list in a new list allowing only read and remove operations.
+ * Addition of new values are not allowed through this {@code RemoveOnlyList}.
+ *
+ * @author  Martin Desruisseaux (Geomatys)
+ * @since   0.8
+ * @version 0.8
+ * @module
+ */
+final class RemoveOnlyList<E> extends AbstractList<E> {
+    /**
+     * The original list to wrap.
+     */
+    private final List<E> elements;
+
+    /**
+     * Creates a new list wrapping the given list.
+     */
+    RemoveOnlyList(final List<E> elements) {
+        this.elements = elements;
+    }
+
+    @Override public void        clear()           {       elements.clear();}
+    @Override public int         size()            {return elements.size();}
+    @Override public E           get(int index)    {return elements.get(index);}
+    @Override public E           remove(int index) {return elements.get(index);}
+    @Override public Iterator<E> iterator()        {return elements.iterator();}
+}

Propchange: sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/builder/RemoveOnlyList.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/builder/RemoveOnlyList.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain;charset=UTF-8

Copied: sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/builder/TypeBuilder.java (from r1752157, sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/internal/feature/FeatureElementBuilder.java)
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/builder/TypeBuilder.java?p2=sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/builder/TypeBuilder.java&p1=sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/internal/feature/FeatureElementBuilder.java&r1=1752157&r2=1752158&rev=1752158&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/internal/feature/FeatureElementBuilder.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/builder/TypeBuilder.java [UTF-8] Mon Jul 11 13:29:44 2016
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.sis.internal.feature;
+package org.apache.sis.feature.builder;
 
 import java.util.Map;
 import java.util.HashMap;
@@ -34,15 +34,28 @@ import org.opengis.feature.IdentifiedTyp
 
 
 /**
- * Base class of feature type, and attribute type, association role and characteristic builders.
+ * Properties common to all kind of types (feature, association, characteristics).
+ * Those properties are:
+ *
+ * <ul>
+ *   <li>the name        — a unique name which can be defined within a scope (or namespace).</li>
+ *   <li>the definition  — a concise definition of the element.</li>
+ *   <li>the designation — a natural language designator for the element for user interfaces.</li>
+ *   <li>the description — information beyond that required for concise definition of the element.</li>
+ * </ul>
+ *
+ * In many cases, all names of the {@code FeatureType} to create share the same namespace.
+ * For making name creations more convenient, a default namespace can be
+ * {@linkplain FeatureTypeBuilder#setDefaultScope specified once} and applied automatically
+ * to all names created by the {@link #setName(String)} method.
  *
  * @author  Johann Sorel (Geomatys)
  * @author  Martin Desruisseaux (Geomatys)
- * @since   0.7
+ * @since   0.8
  * @version 0.8
  * @module
  */
-public abstract class FeatureElementBuilder implements Localized {
+public abstract class TypeBuilder implements Localized {
     /**
      * The feature name, definition, designation and description.
      * The name is mandatory; all other information are optional.
@@ -52,7 +65,7 @@ public abstract class FeatureElementBuil
     /**
      * Creates a new builder initialized to the values of an existing type.
      */
-    FeatureElementBuilder(final IdentifiedType template, final Locale locale) {
+    TypeBuilder(final IdentifiedType template, final Locale locale) {
         putIfNonNull(Errors.LOCALE_KEY, locale);
         if (template != null) {
             putIfNonNull(AbstractIdentifiedType.NAME_KEY,        template.getName());
@@ -158,7 +171,7 @@ public abstract class FeatureElementBuil
      * @see #getName()
      * @see AbstractIdentifiedType#NAME_KEY
      */
-    public FeatureElementBuilder setName(final GenericName name) {
+    public TypeBuilder setName(final GenericName name) {
         ensureNonNull("name", name);
         if (!name.equals(identification.put(AbstractIdentifiedType.NAME_KEY, name))) {
             clearCache();
@@ -180,7 +193,7 @@ public abstract class FeatureElementBuil
      *
      * @see #getName()
      */
-    public FeatureElementBuilder setName(final String localPart) {
+    public TypeBuilder setName(final String localPart) {
         ensureNonEmpty("localPart", localPart);
         return setName(name(null, localPart));
     }
@@ -201,7 +214,7 @@ public abstract class FeatureElementBuil
      *
      * @see #getName()
      */
-    public FeatureElementBuilder setName(String scope, final String localPart) {
+    public TypeBuilder setName(String scope, final String localPart) {
         ensureNonEmpty("localPart", localPart);
         if (scope == null) {
             scope = "";                                 // For preventing the use of default scope.
@@ -229,7 +242,7 @@ public abstract class FeatureElementBuil
      * @see #getDefinition()
      * @see AbstractIdentifiedType#DEFINITION_KEY
      */
-    public FeatureElementBuilder setDefinition(final CharSequence definition) {
+    public TypeBuilder setDefinition(final CharSequence definition) {
         if (!Objects.equals(definition, identification.put(AbstractIdentifiedType.DEFINITION_KEY, definition))) {
             clearCache();
         }
@@ -258,7 +271,7 @@ public abstract class FeatureElementBuil
      * @see #getDesignation()
      * @see AbstractIdentifiedType#DESIGNATION_KEY
      */
-    public FeatureElementBuilder setDesignation(final CharSequence designation) {
+    public TypeBuilder setDesignation(final CharSequence designation) {
         if (!Objects.equals(designation, identification.put(AbstractIdentifiedType.DESIGNATION_KEY, designation))) {
             clearCache();
         }
@@ -287,7 +300,7 @@ public abstract class FeatureElementBuil
      * @see #getDescription()
      * @see AbstractIdentifiedType#DESCRIPTION_KEY
      */
-    public FeatureElementBuilder setDescription(final CharSequence description) {
+    public TypeBuilder setDescription(final CharSequence description) {
         if (!Objects.equals(description, identification.put(AbstractIdentifiedType.DESCRIPTION_KEY, description))) {
             clearCache();
         }

Added: sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/builder/package-info.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/builder/package-info.java?rev=1752158&view=auto
==============================================================================
--- sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/builder/package-info.java (added)
+++ sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/builder/package-info.java [UTF-8] Mon Jul 11 13:29:44 2016
@@ -0,0 +1,27 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Helper class for creating {@code FeatureType} instances.
+ *
+ * @author  Johann Sorel (Geomatys)
+ * @author  Martin Desruisseaux (Geomatys)
+ * @since   0.8
+ * @version 0.8
+ * @module
+ */
+package org.apache.sis.feature.builder;

Propchange: sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/builder/package-info.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/builder/package-info.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain;charset=UTF-8

Modified: sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/internal/feature/AttributeConvention.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/internal/feature/AttributeConvention.java?rev=1752158&r1=1752157&r2=1752158&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/internal/feature/AttributeConvention.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/internal/feature/AttributeConvention.java [UTF-8] Mon Jul 11 13:29:44 2016
@@ -253,7 +253,7 @@ public final class AttributeConvention e
      * @throws ClassCastException if {@link #CRS_CHARACTERISTIC} has been found but is associated
      *         to an object which is not a {@link CoordinateReferenceSystem} instance.
      *
-     * @see org.apache.sis.internal.feature.FeatureTypeBuilder.Property#setCRSCharacteristic(CoordinateReferenceSystem)
+     * @see org.apache.sis.feature.builder.AttributeTypeBuilder#setCRS(CoordinateReferenceSystem)
      */
     public static CoordinateReferenceSystem getCRSCharacteristic(final Property attribute) {
         return (CoordinateReferenceSystem) getCharacteristic(attribute, CRS_CHARACTERISTIC.toString());
@@ -280,7 +280,7 @@ public final class AttributeConvention e
      * @throws ClassCastException if {@link #MAXIMAL_LENGTH_CHARACTERISTIC} has been found but is associated
      *         to an object which is not an {@link Integer} instance.
      *
-     * @see org.apache.sis.internal.feature.FeatureTypeBuilder.Property#setMaximalLengthCharacteristic(Integer)
+     * @see org.apache.sis.feature.builder.AttributeTypeBuilder#setMaximalLength(Integer)
      */
     public static Integer getMaximalLengthCharacteristic(final Property attribute) {
         return (Integer) getCharacteristic(attribute, MAXIMAL_LENGTH_CHARACTERISTIC.toString());

Copied: sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/builder/FeatureTypeBuilderTest.java (from r1752157, sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/internal/feature/FeatureTypeBuilderTest.java)
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/builder/FeatureTypeBuilderTest.java?p2=sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/builder/FeatureTypeBuilderTest.java&p1=sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/internal/feature/FeatureTypeBuilderTest.java&r1=1752157&r2=1752158&rev=1752158&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/internal/feature/FeatureTypeBuilderTest.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/builder/FeatureTypeBuilderTest.java [UTF-8] Mon Jul 11 13:29:44 2016
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.sis.internal.feature;
+package org.apache.sis.feature.builder;
 
 import java.util.Iterator;
 import com.esri.core.geometry.Geometry;
@@ -31,6 +31,7 @@ import org.opengis.feature.AttributeType
 import org.opengis.feature.FeatureType;
 import org.opengis.feature.PropertyType;
 import org.apache.sis.feature.DefaultFeatureTypeTest;
+import org.apache.sis.internal.feature.AttributeConvention;
 import org.apache.sis.test.TestUtilities;
 
 
@@ -39,8 +40,8 @@ import org.apache.sis.test.TestUtilities
  *
  * @author  Johann Sorel (Geomatys)
  * @author  Martin Desruisseaux (Geomatys)
- * @since   0.7
- * @version 0.7
+ * @since   0.8
+ * @version 0.8
  * @module
  */
 public final strictfp class FeatureTypeBuilderTest extends TestCase {
@@ -49,20 +50,20 @@ public final strictfp class FeatureTypeB
      */
     @Test
     public void testEmptyProperty() {
-        final FeatureTypeBuilder.Attribute<String> builder = new FeatureTypeBuilder().addAttribute(String.class);
+        final AttributeTypeBuilder<String> builder = new FeatureTypeBuilder().addAttribute(String.class);
         assertEquals("default name", "string", builder.getName().toString());
 
         builder.setName("myScope", "myName");
         final AttributeType<?> att = (AttributeType<?>) builder.build();
 
-        assertEquals("name",       "myScope:myName", att.getName().toString());
-        assertEquals("valueClass", String.class,     att.getValueClass());
-        assertNull  ("defaultValue",                 att.getDefaultValue());
-        assertNull  ("definition",                   att.getDefinition());
-        assertNull  ("description",                  att.getDescription());
-        assertNull  ("designation",                  att.getDesignation());
-        assertEquals("minimumOccurs", 1,             att.getMinimumOccurs());
-        assertEquals("maximumOccurs", 1,             att.getMaximumOccurs());
+        assertEquals("name", "myScope:myName",   att.getName().toString());
+        assertEquals("valueClass", String.class, att.getValueClass());
+        assertNull  ("defaultValue",             att.getDefaultValue());
+        assertNull  ("definition",               att.getDefinition());
+        assertNull  ("description",              att.getDescription());
+        assertNull  ("designation",              att.getDesignation());
+        assertEquals("minimumOccurs", 1,         att.getMinimumOccurs());
+        assertEquals("maximumOccurs", 1,         att.getMaximumOccurs());
     }
 
     /**
@@ -101,14 +102,14 @@ public final strictfp class FeatureTypeB
     @Test
     @DependsOnMethod("testEmptyProperty")
     public void testPropertyBuild() {
-        final FeatureTypeBuilder.Attribute<String> builder = new FeatureTypeBuilder().addAttribute(String.class);
+        final AttributeTypeBuilder<String> builder = new FeatureTypeBuilder().addAttribute(String.class);
         builder.setName        ("myScope", "myName");
         builder.setDefinition  ("test definition");
         builder.setDesignation ("test designation");
         builder.setDescription ("test description");
         builder.setDefaultValue("test default value.");
         builder.setCardinality(10, 60);
-        builder.setMaximalLengthCharacteristic(80);
+        builder.setMaximalLength(80);
         final AttributeType<?> att = (AttributeType<?>) builder.build();
 
         assertEquals("name",          "myScope:myName",      att.getName().toString());
@@ -144,7 +145,7 @@ public final strictfp class FeatureTypeB
         builder.setAbstract(true);
         builder.addAttribute(String .class).setName("name");
         builder.addAttribute(Integer.class).setName("age");
-        builder.addAttribute(Point  .class).setName("location").setCRSCharacteristic(HardCodedCRS.WGS84);
+        builder.addAttribute(Point  .class).setName("location").setCRS(HardCodedCRS.WGS84);
         builder.addAttribute(Double .class).setName("score").setDefaultValue(10.0).setCardinality(5, 50);
 
         final FeatureType type = builder.build();
@@ -202,10 +203,10 @@ public final strictfp class FeatureTypeB
         builder.setName("scope", "test");
         builder.setIdentifierDelimiters("-", "pref.", null);
         builder.addAttribute(String.class).setName("name")
-                .addRole(FeatureTypeBuilder.Attribute.Role.IDENTIFIER_COMPONENT);
+                .addRole(AttributeRole.IDENTIFIER_COMPONENT);
         builder.addAttribute(Geometry.class).setName("shape")
-                .setCRSCharacteristic(HardCodedCRS.WGS84)
-                .addRole(FeatureTypeBuilder.Attribute.Role.DEFAULT_GEOMETRY);
+                .setCRS(HardCodedCRS.WGS84)
+                .addRole(AttributeRole.DEFAULT_GEOMETRY);
 
         final FeatureType type = builder.build();
         assertEquals("name", "scope:test", type.getName().toString());

Modified: sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/test/suite/FeatureTestSuite.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/test/suite/FeatureTestSuite.java?rev=1752158&r1=1752157&r2=1752158&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/test/suite/FeatureTestSuite.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/test/suite/FeatureTestSuite.java [UTF-8] Mon Jul 11 13:29:44 2016
@@ -51,7 +51,7 @@ import org.junit.BeforeClass;
     org.apache.sis.filter.DefaultLiteralTest.class,
     org.apache.sis.filter.DefaultPropertyNameTest.class,
     org.apache.sis.internal.feature.AttributeConventionTest.class,
-    org.apache.sis.internal.feature.FeatureTypeBuilderTest.class
+    org.apache.sis.feature.builder.FeatureTypeBuilderTest.class
 })
 public final strictfp class FeatureTestSuite extends TestSuite {
     /**



Mime
View raw message