sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1640352 [1/2] - in /sis/trunk: ./ core/sis-feature/src/main/java/org/apache/sis/feature/ core/sis-feature/src/test/java/org/apache/sis/feature/ core/sis-feature/src/test/java/org/apache/sis/test/suite/ core/sis-metadata/src/main/java/org/a...
Date Tue, 18 Nov 2014 14:44:12 GMT
Author: desruisseaux
Date: Tue Nov 18 14:44:11 2014
New Revision: 1640352

URL: http://svn.apache.org/r1640352
Log:
Merge from the JDK6 branch.
The main work is "attribute on attributes" of features derived from ISO 19109 UML schema.

Added:
    sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/CharacteristicMap.java
      - copied, changed from r1640308, sis/branches/JDK6/core/sis-feature/src/main/java/org/apache/sis/feature/CharacteristicMap.java
    sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/CharacteristicTypeMap.java
      - copied, changed from r1640308, sis/branches/JDK6/core/sis-feature/src/main/java/org/apache/sis/feature/CharacteristicTypeMap.java
    sis/trunk/core/sis-feature/src/test/java/org/apache/sis/feature/CharacteristicMapTest.java
      - copied, changed from r1640308, sis/branches/JDK6/core/sis-feature/src/test/java/org/apache/sis/feature/CharacteristicMapTest.java
    sis/trunk/core/sis-feature/src/test/java/org/apache/sis/feature/CharacteristicTypeMapTest.java
      - copied, changed from r1640308, sis/branches/JDK6/core/sis-feature/src/test/java/org/apache/sis/feature/CharacteristicTypeMapTest.java
    sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/util/AbstractMap.java
      - copied unchanged from r1640308, sis/branches/JDK6/core/sis-utility/src/main/java/org/apache/sis/internal/util/AbstractMap.java
    sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/util/AbstractMapEntry.java
      - copied unchanged from r1640308, sis/branches/JDK6/core/sis-utility/src/main/java/org/apache/sis/internal/util/AbstractMapEntry.java
    sis/trunk/core/sis-utility/src/test/java/org/apache/sis/internal/util/AbstractMapTest.java
      - copied unchanged from r1640308, sis/branches/JDK6/core/sis-utility/src/test/java/org/apache/sis/internal/util/AbstractMapTest.java
Modified:
    sis/trunk/   (props changed)
    sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractAssociation.java
    sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractAttribute.java
    sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractFeature.java   (contents, props changed)
    sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractIdentifiedType.java
    sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultAssociationRole.java
    sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultAttributeType.java
    sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultFeatureType.java
    sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/Features.java
    sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/FieldType.java
    sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/MultiValuedAssociation.java
    sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/MultiValuedAttribute.java
    sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/PropertySingleton.java
    sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/SingletonAssociation.java
    sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/SingletonAttribute.java
    sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/SparseFeature.java   (contents, props changed)
    sis/trunk/core/sis-feature/src/test/java/org/apache/sis/feature/DefaultAttributeTypeTest.java
    sis/trunk/core/sis-feature/src/test/java/org/apache/sis/feature/MultiValuedAttributeTest.java
    sis/trunk/core/sis-feature/src/test/java/org/apache/sis/feature/SingletonAttributeTest.java
    sis/trunk/core/sis-feature/src/test/java/org/apache/sis/test/suite/FeatureTestSuite.java
    sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/ValueMap.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/Properties.java
    sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/IdentifierMapAdapter.java
    sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/collection/Cache.java
    sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/collection/WeakEntry.java
    sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/collection/WeakValueHashMap.java
    sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultRecord.java
    sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java
    sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties
    sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties
    sis/trunk/core/sis-utility/src/test/java/org/apache/sis/test/suite/UtilityTestSuite.java

Propchange: sis/trunk/
------------------------------------------------------------------------------
  Merged /sis/branches/JDK8:r1637099-1640283
  Merged /sis/branches/JDK7:r1637101-1640304
  Merged /sis/branches/JDK6:r1637103-1640308

Modified: sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractAssociation.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractAssociation.java?rev=1640352&r1=1640351&r2=1640352&view=diff
==============================================================================
--- sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractAssociation.java [UTF-8] (original)
+++ sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractAssociation.java [UTF-8] Tue Nov 18 14:44:11 2014
@@ -28,6 +28,7 @@ import org.apache.sis.util.resources.Err
 
 /**
  * An instance of an {@linkplain DefaultAssociationRole feature association role} containing the associated feature.
+ * {@code AbstractAssociation} can be instantiated by calls to {@link DefaultAssociationRole#newInstance()}.
  *
  * {@section Limitations}
  * <ul>
@@ -43,9 +44,9 @@ import org.apache.sis.util.resources.Err
  * @version 0.5
  * @module
  *
- * @see DefaultAssociationRole
+ * @see DefaultAssociationRole#newInstance()
  */
-public abstract class AbstractAssociation extends Field<AbstractFeature> implements Serializable {
+public abstract class AbstractAssociation extends Field<AbstractFeature> implements Cloneable, Serializable {
     /**
      * For cross-version compatibility.
      */
@@ -72,6 +73,8 @@ public abstract class AbstractAssociatio
      *
      * @param  role Information about the association.
      * @return The new association.
+     *
+     * @see DefaultAssociationRole#newInstance()
      */
     public static AbstractAssociation create(final DefaultAssociationRole role) {
         ArgumentChecks.ensureNonNull("role", role);
@@ -238,6 +241,21 @@ public abstract class AbstractAssociatio
             public void remove() {
                 throw new UnsupportedOperationException();
             }
-        });
+        }).toString();
+    }
+
+    /**
+     * Returns a copy of this association.
+     * The default implementation returns a <em>shallow</em> copy:
+     * the association {@linkplain #getValue() value} is <strong>not</strong> cloned.
+     * However subclasses may choose to do otherwise.
+     *
+     * @return A clone of this association.
+     * @throws CloneNotSupportedException if this association can not be cloned.
+     *         The default implementation never throw this exception. However subclasses may throw it.
+     */
+    @Override
+    public AbstractAssociation clone() throws CloneNotSupportedException {
+        return (AbstractAssociation) super.clone();
     }
 }

Modified: sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractAttribute.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractAttribute.java?rev=1640352&r1=1640351&r2=1640352&view=diff
==============================================================================
--- sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractAttribute.java [UTF-8] (original)
+++ sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractAttribute.java [UTF-8] Tue Nov 18 14:44:11 2014
@@ -16,8 +16,15 @@
  */
 package org.apache.sis.feature;
 
+import java.util.Map;
+import java.util.Arrays;
 import java.util.Collection;
+import java.util.Collections;
 import java.io.Serializable;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.InvalidObjectException;
+import java.io.IOException;
 import org.opengis.util.GenericName;
 import org.opengis.metadata.quality.DataQuality;
 import org.opengis.metadata.maintenance.ScopeCode;
@@ -25,17 +32,24 @@ import org.apache.sis.util.Debug;
 import org.apache.sis.util.Classes;
 import org.apache.sis.util.ArgumentChecks;
 
+import org.apache.sis.internal.jdk7.JDK7;
 
 /**
  * An instance of an {@linkplain DefaultAttributeType attribute type} containing the value of an attribute in a feature.
- * {@code Attribute} holds two main information:
+ * {@code Attribute} holds three main information:
  *
  * <ul>
- *   <li>A reference to an {@linkplain DefaultAttributeType attribute type}
+ *   <li>A {@linkplain #getType() reference to an attribute type}
  *       which define the base Java type and domain of valid values.</li>
- *   <li>A value, which may be a singleton ([0 … 1] cardinality) or multi-valued ([0 … ∞] cardinality).</li>
+ *   <li>One or more {@linkplain #getValues() values}, which may be a singleton ([0 … 1] cardinality)
+ *       or multi-valued ([0 … ∞] cardinality).</li>
+ *   <li>Optional {@linkplain #characteristics() characteristics} about the attribute
+ *       (e.g. a <var>temperature</var> attribute may have a characteristic holding the measurement <var>accuracy</var>).
+ *       Characteristics are often, but not necessarily, constant for all attributes of the same type in a dataset.</li>
  * </ul>
  *
+ * {@code AbstractAttribute} can be instantiated by calls to {@link DefaultAttributeType#newInstance()}.
+ *
  * {@section Limitations}
  * <ul>
  *   <li><b>Multi-threading:</b> {@code AbstractAttribute} instances are <strong>not</strong> thread-safe.
@@ -53,9 +67,9 @@ import org.apache.sis.util.ArgumentCheck
  * @version 0.5
  * @module
  *
- * @see DefaultAttributeType
+ * @see DefaultAttributeType#newInstance()
  */
-public abstract class AbstractAttribute<V> extends Field<V> implements Serializable {
+public abstract class AbstractAttribute<V> extends Field<V> implements Cloneable, Serializable {
     /**
      * For cross-version compatibility.
      */
@@ -67,6 +81,21 @@ public abstract class AbstractAttribute<
     final DefaultAttributeType<V> type;
 
     /**
+     * Other attributes that describes this attribute, or {@code null} if not yet created.
+     *
+     * <div class="note"><b>Design note:</b>
+     * We could question if it is a good idea to put this field here, given that this field add a slight cost
+     * to all attribute implementations while only a small fraction of them will want attribute characteristics.
+     * Since attributes may exist in a very large amount, that question may be significant.
+     * However {@link AbstractFeature} tries hard to not create {@code Attribute} instances at all (it tries to
+     * store only their value instead), so we presume that peoples who ask for {@code Attribute} instances are
+     * willing to accept their cost.</div>
+     *
+     * @see #characteristics()
+     */
+    private transient Map<String,AbstractAttribute<?>> characteristics;
+
+    /**
      * Creates a new attribute of the given type.
      *
      * @param type Information about the attribute (base Java class, domain of values, <i>etc.</i>).
@@ -84,6 +113,8 @@ public abstract class AbstractAttribute<
      * @param  <V>  The type of attribute values.
      * @param  type Information about the attribute (base Java class, domain of values, <i>etc.</i>).
      * @return The new attribute.
+     *
+     * @see DefaultAttributeType#newInstance()
      */
     public static <V> AbstractAttribute<V> create(final DefaultAttributeType<V> type) {
         ArgumentChecks.ensureNonNull("type", type);
@@ -109,6 +140,43 @@ public abstract class AbstractAttribute<
     }
 
     /**
+     * Invoked on serialization for saving the {@link #characteristics} field.
+     *
+     * @param  out The output stream where to serialize this attribute.
+     * @throws IOException If an I/O error occurred while writing.
+     */
+    private void writeObject(final ObjectOutputStream out) throws IOException {
+        out.defaultWriteObject();
+        final AbstractAttribute<?>[] characterizedBy;
+        if (characteristics instanceof CharacteristicMap) {
+            characterizedBy = characteristics.values().toArray(new AbstractAttribute<?>[characteristics.size()]);
+        } else {
+            characterizedBy = null;
+        }
+        out.writeObject(characterizedBy);
+    }
+
+    /**
+     * Invoked on deserialization for restoring the {@link #characteristics} field.
+     *
+     * @param  in The input stream from which to deserialize an attribute.
+     * @throws IOException If an I/O error occurred while reading or if the stream contains invalid data.
+     * @throws ClassNotFoundException If the class serialized on the stream is not on the classpath.
+     */
+    private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException {
+        in.defaultReadObject();
+        try {
+            final AbstractAttribute<?>[] characterizedBy = (AbstractAttribute<?>[]) in.readObject();
+            if (characterizedBy != null) {
+                characteristics = newCharacteristicsMap();
+                characteristics.values().addAll(Arrays.asList(characterizedBy));
+            }
+        } catch (RuntimeException e) { // At least ClassCastException, NullPointerException, IllegalArgumentException and IllegalStateException.
+            throw (IOException) new InvalidObjectException(e.getMessage()).initCause(e);
+        }
+    }
+
+    /**
      * Returns the name of this attribute as defined by its {@linkplain #getType() type}.
      * This convenience method delegates to {@link DefaultAttributeType#getName()}.
      *
@@ -190,6 +258,112 @@ public abstract class AbstractAttribute<
     }
 
     /**
+     * Other attributes that describes this attribute. For example if this attribute carries a measurement,
+     * then a characteristic of this attribute could be the measurement accuracy.
+     * See "<cite>Attribute characterization</cite>" in {@link DefaultAttributeType} Javadoc for more information.
+     *
+     * <p>The map returned by this method contains only the characteristics explicitely defined for this attribute.
+     * If the map contains no characteristic for a given name, a {@linkplain DefaultAttributeType#getDefaultValue()
+     * default value} may still exist.
+     * In such cases, callers may also need to inspect the {@link DefaultAttributeType#characteristics()}
+     * as shown in the <cite>Reading a characteristic</cite> section below.</p>
+     *
+     * <div class="note"><b>Rational:</b>
+     * Very often, all attributes of a given type in the same dataset have the same characteristics.
+     * For example it is very common that all temperature measurements in a dataset have the same accuracy,
+     * and setting a different accuracy for a single measurement is relatively rare.
+     * Consequently, {@code characteristics.isEmpty()} is a convenient way to check that an attribute have
+     * all the "standard" characteristics and need no special processing.</div>
+     *
+     * {@section Reading a characteristic}
+     * If an attribute is known to be a measurement with a characteristic named "accuracy" of type {@link Float},
+     * then the accuracy value could be read as below:
+     *
+     * {@preformat java
+     *     Float getAccuracy(Attribute<?> measurement) {
+     *         Attribute<?> accuracy = measurement.characteristics().get("accuracy");
+     *         if (accuracy != null) {
+     *             return (Float) accuracy.getValue(); // Value may be null.
+     *         } else {
+     *             return (Float) measurement.getType().characteristics().get("accuracy").getDefaultValue();
+     *             // A more sophisticated implementation would probably cache the default value somewhere.
+     *         }
+     *     }
+     * }
+     *
+     * {@section Adding a characteristic}
+     * A new characteristic can be added in the map in three different ways:
+     * <ol>
+     *   <li>Putting the (<var>name</var>, <var>characteristic</var>) pair explicitely.
+     *     If an older characteristic existed for that name, it will be replaced.
+     *     Example:
+     *
+     *     {@preformat java
+     *       Attribute<?> accuracy = ...; // To be created by the caller.
+     *       characteristics.put("accuracy", accuracy);
+     *     }</li>
+     *
+     *   <li>Adding the new characteristic to the {@linkplain Map#values() values} collection.
+     *     The name is inferred automatically from the characteristic type.
+     *     If an older characteristic existed for the same name, an {@link IllegalStateException} will be thrown.
+     *     Example:
+     *
+     *     {@preformat java
+     *       Attribute<?> accuracy = ...; // To be created by the caller.
+     *       characteristics.values().add(accuracy);
+     *     }</li>
+     *
+     *   <li>Adding the characteristic name to the {@linkplain Map#keySet() key set}.
+     *     If no characteristic existed for that name, a default one will be created.
+     *     Example:
+     *
+     *     {@preformat java
+     *       characteristics.keySet().add("accuracy"); // Ensure that an entry will exist for that name.
+     *       Attribute<?> accuracy = characteristics.get("accuracy");
+     *       Features.cast(accuracy, Float.class).setValue(...); // Set new accuracy value here as a float.
+     *     }</li>
+     * </ol>
+     *
+     * @return Other attribute types that describes this attribute type, or an empty set if none.
+     *
+     * @see DefaultAttributeType#characteristics()
+     */
+    public Map<String,AbstractAttribute<?>> characteristics() {
+        if (characteristics == null) {
+            characteristics = newCharacteristicsMap();
+        }
+        return characteristics;
+    }
+
+    /**
+     * Creates an initially empty map of characteristics for this attribute.
+     * This method does not store the new map in the {@link #characteristics} field;
+     * it is caller responsibility to do so if desired.
+     */
+    private Map<String,AbstractAttribute<?>> newCharacteristicsMap() {
+        if (type instanceof DefaultAttributeType<?>) {
+            Map<String, DefaultAttributeType<?>> map = type.characteristics();
+            if (!map.isEmpty()) {
+                if (!(map instanceof CharacteristicTypeMap)) {
+                    final Collection<DefaultAttributeType<?>> types = map.values();
+                    map = CharacteristicTypeMap.create(type, types.toArray(new DefaultAttributeType<?>[types.size()]));
+                }
+                return new CharacteristicMap(this, (CharacteristicTypeMap) map);
+            }
+        }
+        return Collections.emptyMap();
+    }
+
+    /**
+     * Returns the characteristics, or an empty map if the characteristics have not yet been built.
+     * Contrarily to {@link #characteristics()}, this method does not create the map. This method
+     * is suitable when then caller only wants to read the map and does not plan to write anything.
+     */
+    final Map<String,AbstractAttribute<?>> characteristicsReadOnly() {
+        return (characteristics != null) ? characteristics : Collections.<String,AbstractAttribute<?>>emptyMap();
+    }
+
+    /**
      * Evaluates the quality of this attribute at this method invocation time. The data quality reports
      * may include information about whether the attribute value mets the constraints defined by the
      * {@linkplain DefaultAttributeType attribute type}, or any other criterion at implementation choice.
@@ -266,12 +440,50 @@ public abstract class AbstractAttribute<
     /**
      * Returns a string representation of this attribute.
      * The returned string is for debugging purpose and may change in any future SIS version.
+     * The current implementation is like below:
+     *
+     * {@preformat text
+     *     Attribute[“temperature” : Float] = {20.3, 17.8, 21.1}
+     *     └─ characteristics: units=°C, accuracy=0.1
+     * }
      *
      * @return A string representation of this attribute for debugging purpose.
      */
     @Debug
     @Override
     public String toString() {
-        return FieldType.toString("Attribute", type, Classes.getShortName(type.getValueClass()), getValues().iterator());
+        final StringBuilder buffer = FieldType.toString("Attribute", type,
+                Classes.getShortName(type.getValueClass()), getValues().iterator());
+        if (characteristics != null && !characteristics.isEmpty()) {
+            buffer.append(JDK7.lineSeparator());
+            String separator = "└─ characteristics: ";
+            for (final Map.Entry<String,AbstractAttribute<?>> entry : characteristics.entrySet()) {
+                buffer.append(separator).append(entry.getKey()).append('=').append(entry.getValue().getValue());
+                separator = ", ";
+            }
+        }
+        return buffer.toString();
+    }
+
+    /**
+     * Returns a copy of this attribute.
+     * The default implementation returns a <em>shallow</em> copy:
+     * the attribute {@linkplain #getValue() value} and {@linkplain #characteristics() characteristics}
+     * are <strong>not</strong> cloned.
+     * However subclasses may choose to do otherwise.
+     *
+     * @return A clone of this attribute.
+     * @throws CloneNotSupportedException if this attribute, the {@linkplain #getValue() value}
+     *         or one of its {@linkplain #characteristics() characteristics} can not be cloned.
+     */
+    @Override
+    @SuppressWarnings("unchecked")
+    public AbstractAttribute<V> clone() throws CloneNotSupportedException {
+        final AbstractAttribute<V> clone = (AbstractAttribute<V>) super.clone();
+        final Map<String,AbstractAttribute<?>> c = clone.characteristics;
+        if (c instanceof CharacteristicMap) {
+            clone.characteristics = ((CharacteristicMap) c).clone();
+        }
+        return clone;
     }
 }

Modified: sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractFeature.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractFeature.java?rev=1640352&r1=1640351&r2=1640352&view=diff
==============================================================================
--- sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractFeature.java [UTF-8] (original)
+++ sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractFeature.java [UTF-8] Tue Nov 18 14:44:11 2014
@@ -381,7 +381,7 @@ public abstract class AbstractFeature im
     }
 
     /**
-     * Verifies if the given properties can be assigned to this feature.
+     * Verifies if the given property can be assigned to this feature.
      *
      * @param name Shall be {@code property.getName().toString()}.
      * @param property The property to verify.
@@ -396,7 +396,9 @@ public abstract class AbstractFeature im
             throw illegalPropertyType(base.getName(), property.getClass());
         }
         if (pt != base) {
-            throw new IllegalArgumentException(Errors.format(Errors.Keys.MismatchedPropertyType_1, name));
+            throw new IllegalArgumentException(base == null
+                    ? Errors.format(Errors.Keys.PropertyNotFound_2, getName(), name)
+                    : Errors.format(Errors.Keys.MismatchedPropertyType_1, name));
         }
     }
 

Propchange: sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractFeature.java
------------------------------------------------------------------------------
  Merged /sis/branches/JDK6/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractFeature.java:r1601003-1640308
  Merged /sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractFeature.java:r1600998-1640283
  Merged /sis/branches/JDK7/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractFeature.java:r1601000-1640304

Modified: sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractIdentifiedType.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractIdentifiedType.java?rev=1640352&r1=1640351&r2=1640352&view=diff
==============================================================================
--- sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractIdentifiedType.java [UTF-8] (original)
+++ sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractIdentifiedType.java [UTF-8] Tue Nov 18 14:44:11 2014
@@ -288,4 +288,30 @@ public class AbstractIdentifiedType impl
         }
         return false;
     }
+
+    /**
+     * Returns the string representation of the given name, making sure that the name is non-null
+     * and the string non-empty. This method is used for checking argument validity.
+     *
+     * @param name      The name for which to get the string representation.
+     * @param container The feature or attribute which contains the named characteristics.
+     * @param argument  The name of the argument ({@code "properties"} or {@code "characterizedBy"}).
+     * @param index     Index of the characteristics having the given name.
+     * @throws IllegalArgumentException if the given name is null or have an empty string representation.
+     */
+    static String toString(final GenericName name, final AbstractIdentifiedType container,
+            final String argument, final int index)
+    {
+        short key = Errors.Keys.MissingValueForProperty_1;
+        if (name != null) {
+            final String s = name.toString();
+            if (!s.isEmpty()) {
+                return s;
+            }
+            key = Errors.Keys.EmptyProperty_1;
+        }
+        final StringBuilder b = new StringBuilder(40).append("Type[“").append(container.getName()).append("”].")
+                .append(argument).append('[').append(index).append("].name");
+        throw new IllegalArgumentException(Errors.format(key, b.toString()));
+    }
 }

Copied: sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/CharacteristicMap.java (from r1640308, sis/branches/JDK6/core/sis-feature/src/main/java/org/apache/sis/feature/CharacteristicMap.java)
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/CharacteristicMap.java?p2=sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/CharacteristicMap.java&p1=sis/branches/JDK6/core/sis-feature/src/main/java/org/apache/sis/feature/CharacteristicMap.java&r1=1640308&r2=1640352&rev=1640352&view=diff
==============================================================================
--- sis/branches/JDK6/core/sis-feature/src/main/java/org/apache/sis/feature/CharacteristicMap.java [UTF-8] (original)
+++ sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/CharacteristicMap.java [UTF-8] Tue Nov 18 14:44:11 2014
@@ -24,10 +24,6 @@ import org.apache.sis.internal.util.Clon
 import org.apache.sis.internal.util.AbstractMap;
 import org.apache.sis.internal.util.AbstractMapEntry;
 
-// Branch-dependent imports
-import org.opengis.feature.Attribute;
-import org.opengis.feature.AttributeType;
-
 
 /**
  * Implementation of {@link AbstractAttribute#characteristics()} map.
@@ -38,16 +34,16 @@ import org.opengis.feature.AttributeType
  * @version 0.5
  * @module
  */
-final class CharacteristicMap extends AbstractMap<String,Attribute<?>> implements Cloneable {
+final class CharacteristicMap extends AbstractMap<String,AbstractAttribute<?>> implements Cloneable {
     /**
      * The attribute source for which to provide characteristics.
      */
-    private final Attribute<?> source;
+    private final AbstractAttribute<?> source;
 
     /**
      * Characteristics of the {@code source} attribute, created when first needed.
      */
-    Attribute<?>[] characterizedBy;
+    AbstractAttribute<?>[] characterizedBy;
 
     /**
      * Description of the attribute characteristics.
@@ -60,7 +56,7 @@ final class CharacteristicMap extends Ab
      * @param source The attribute which is characterized by {@code characterizedBy}.
      * @param characterizedBy Description of the characteristics of {@code source}.
      */
-    CharacteristicMap(final Attribute<?> source, final CharacteristicTypeMap types) {
+    CharacteristicMap(final AbstractAttribute<?> source, final CharacteristicTypeMap types) {
         this.source = source;
         this.types  = types;
     }
@@ -73,14 +69,14 @@ final class CharacteristicMap extends Ab
     @Override
     public CharacteristicMap clone() throws CloneNotSupportedException {
         final CharacteristicMap clone = (CharacteristicMap) super.clone();
-        Attribute<?>[] c = clone.characterizedBy;
+        AbstractAttribute<?>[] c = clone.characterizedBy;
         if (c != null) {
             clone.characterizedBy = c = c.clone();
             final Cloner cloner = new Cloner();
             for (int i=0; i<c.length; i++) {
-                final Attribute<?> attribute = c[i];
+                final AbstractAttribute<?> attribute = c[i];
                 if (attribute instanceof Cloneable) {
-                    c[i] = (Attribute<?>) cloner.clone(attribute);
+                    c[i] = (AbstractAttribute<?>) cloner.clone(attribute);
                 }
             }
         }
@@ -106,7 +102,7 @@ final class CharacteristicMap extends Ab
     @Override
     public boolean isEmpty() {
         if (characterizedBy != null) {
-            for (final Attribute<?> attribute : characterizedBy) {
+            for (final AbstractAttribute<?> attribute : characterizedBy) {
                 if (attribute != null) {
                     return false;
                 }
@@ -122,7 +118,7 @@ final class CharacteristicMap extends Ab
     public int size() {
         int n = 0;
         if (characterizedBy != null) {
-            for (final Attribute<?> attribute : characterizedBy) {
+            for (final AbstractAttribute<?> attribute : characterizedBy) {
                 if (attribute != null) {
                     n++;
                 }
@@ -135,7 +131,7 @@ final class CharacteristicMap extends Ab
      * Returns the attribute characteristic for the given name, or {@code null} if none.
      */
     @Override
-    public Attribute<?> get(final Object key) {
+    public AbstractAttribute<?> get(final Object key) {
         if (characterizedBy != null) {
             final Integer index = types.indices.get(key);
             if (index != null) {
@@ -149,11 +145,11 @@ final class CharacteristicMap extends Ab
      * Removes the attribute characteristic for the given name.
      */
     @Override
-    public Attribute<?> remove(final Object key) {
+    public AbstractAttribute<?> remove(final Object key) {
         if (characterizedBy != null) {
             final Integer index = types.indices.get(key);
             if (index != null) {
-                final Attribute<?> previous = characterizedBy[index];
+                final AbstractAttribute<?> previous = characterizedBy[index];
                 characterizedBy[index] = null;
                 return previous;
             }
@@ -185,8 +181,8 @@ final class CharacteristicMap extends Ab
      * @param index Index of the expected attribute type.
      * @param type  The actual attribute type.
      */
-    final void verifyAttributeType(final int index, final AttributeType<?> type) {
-        final AttributeType<?> expected = types.characterizedBy[index];
+    final void verifyAttributeType(final int index, final DefaultAttributeType<?> type) {
+        final DefaultAttributeType<?> expected = types.characterizedBy[index];
         if (!expected.equals(type)) {
             final GenericName en = expected.getName();
             final GenericName an = type.getName();
@@ -203,14 +199,14 @@ final class CharacteristicMap extends Ab
      * @throws IllegalArgumentException if the given key is not the name of a characteristic in this map.
      */
     @Override
-    public Attribute<?> put(final String key, final Attribute<?> value) {
+    public AbstractAttribute<?> put(final String key, final AbstractAttribute<?> value) {
         final int index = indexOf(key);
         ArgumentChecks.ensureNonNull("value", value);
         verifyAttributeType(index, value.getType());
         if (characterizedBy == null) {
-            characterizedBy = new Attribute<?>[types.characterizedBy.length];
+            characterizedBy = new AbstractAttribute<?>[types.characterizedBy.length];
         }
-        final Attribute<?> previous = characterizedBy[index];
+        final AbstractAttribute<?> previous = characterizedBy[index];
         characterizedBy[index] = value;
         return previous;
     }
@@ -227,7 +223,7 @@ final class CharacteristicMap extends Ab
     protected boolean addKey(final String name) {
         final int index = indexOf(name);
         if (characterizedBy == null) {
-            characterizedBy = new Attribute<?>[types.characterizedBy.length];
+            characterizedBy = new AbstractAttribute<?>[types.characterizedBy.length];
         }
         if (characterizedBy[index] == null) {
             characterizedBy[index] = AbstractAttribute.create(types.characterizedBy[index]);
@@ -245,14 +241,14 @@ final class CharacteristicMap extends Ab
      * @throws IllegalStateException if another characteristic already exists for the characteristic name.
      */
     @Override
-    protected boolean addValue(final Attribute<?> value) {
+    protected boolean addValue(final AbstractAttribute<?> value) {
         ArgumentChecks.ensureNonNull("value", value);
         final int index = indexOf(value.getName().toString());
         verifyAttributeType(index, value.getType());
         if (characterizedBy == null) {
-            characterizedBy = new Attribute<?>[types.characterizedBy.length];
+            characterizedBy = new AbstractAttribute<?>[types.characterizedBy.length];
         }
-        final Attribute<?> previous = characterizedBy[index];
+        final AbstractAttribute<?> previous = characterizedBy[index];
         if (previous == null) {
             characterizedBy[index] = value;
             return true;
@@ -268,16 +264,16 @@ final class CharacteristicMap extends Ab
      * Returns an iterator over the entries.
      */
     @Override
-    protected EntryIterator<String, Attribute<?>> entryIterator() {
+    protected EntryIterator<String, AbstractAttribute<?>> entryIterator() {
         if (characterizedBy == null) {
             return null;
         }
-        return new EntryIterator<String, Attribute<?>>() {
+        return new EntryIterator<String, AbstractAttribute<?>>() {
             /** Index of the current element to return in the iteration. */
             private int index = -1;
 
             /** The element to return, or {@code null} if we reached the end of iteration. */
-            private Attribute<?> value;
+            private AbstractAttribute<?> value;
 
             /** Returns {@code true} if there is more entries in the iteration. */
             @Override protected boolean next() {
@@ -295,12 +291,12 @@ final class CharacteristicMap extends Ab
             }
 
             /** Returns the attribute characteristic (never {@code null}). */
-            @Override protected Attribute<?> getValue() {
+            @Override protected AbstractAttribute<?> getValue() {
                 return value;
             }
 
             /** Creates and return the next entry. */
-            @Override protected Map.Entry<String, Attribute<?>> getEntry() {
+            @Override protected Map.Entry<String, AbstractAttribute<?>> getEntry() {
                 return new Entry(index, value);
             }
 
@@ -316,15 +312,15 @@ final class CharacteristicMap extends Ab
      * The key and value are never null, even in case of concurrent modification.
      * This entry supports the {@link #setValue(Attribute)} operation.
      */
-    private final class Entry extends AbstractMapEntry<String, Attribute<?>> {
+    private final class Entry extends AbstractMapEntry<String, AbstractAttribute<?>> {
         /** Index of the attribute characteristics represented by this entry. */
         private final int index;
 
         /** The current attribute value, which is guaranteed to be non-null. */
-        private Attribute<?> value;
+        private AbstractAttribute<?> value;
 
         /** Creates a new entry for the characteristic at the given index. */
-        Entry(final int index, final Attribute<?> value) {
+        Entry(final int index, final AbstractAttribute<?> value) {
             this.index = index;
             this.value = value;
         }
@@ -335,15 +331,15 @@ final class CharacteristicMap extends Ab
         }
 
         /** Returns the attribute characteristic (never {@code null}). */
-        @Override public Attribute<?> getValue() {
+        @Override public AbstractAttribute<?> getValue() {
             return value;
         }
 
         /** Sets the attribute characteristic. */
-        @Override public Attribute<?> setValue(final Attribute<?> value) {
+        @Override public AbstractAttribute<?> setValue(final AbstractAttribute<?> value) {
             ArgumentChecks.ensureNonNull("value", value);
             verifyAttributeType(index, value.getType());
-            final Attribute<?> previous = this.value;
+            final AbstractAttribute<?> previous = this.value;
             characterizedBy[index] = value;
             this.value = value;
             return previous;

Copied: sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/CharacteristicTypeMap.java (from r1640308, sis/branches/JDK6/core/sis-feature/src/main/java/org/apache/sis/feature/CharacteristicTypeMap.java)
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/CharacteristicTypeMap.java?p2=sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/CharacteristicTypeMap.java&p1=sis/branches/JDK6/core/sis-feature/src/main/java/org/apache/sis/feature/CharacteristicTypeMap.java&r1=1640308&r2=1640352&rev=1640352&view=diff
==============================================================================
--- sis/branches/JDK6/core/sis-feature/src/main/java/org/apache/sis/feature/CharacteristicTypeMap.java [UTF-8] (original)
+++ sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/CharacteristicTypeMap.java [UTF-8] Tue Nov 18 14:44:11 2014
@@ -26,9 +26,6 @@ import org.apache.sis.util.resources.Err
 
 import static org.apache.sis.util.ArgumentChecks.ensureNonNullElement;
 
-// Branch-dependent imports
-import org.opengis.feature.AttributeType;
-
 
 /**
  * Implementation of the map returned by {@link DefaultAttributeType#characteristics()}.
@@ -38,7 +35,7 @@ import org.opengis.feature.AttributeType
  * The straightforward approach would be to store the attributes directly as values in a standard {@code HashMap}.
  * But instead of that, we store attributes in an array and the array indices in a {@code HashMap}. This level of
  * indirection is useless if we consider only the {@link DefaultAttributeType#characteristics()} method, since a
- * standard {@code HashMap<String,AttributeType>} would work as well or better. However this level of indirection
+ * standard {@code HashMap<String,DefaultAttributeType>} would work as well or better. However this level of indirection
  * become useful for {@link CharacteristicMap} (the map returned by {@link DefaultAttribute#characteristics()}),
  * since it allows a more efficient storage. We do this effort because some applications may create a very large
  * amount of attribute instances.</p>
@@ -48,17 +45,17 @@ import org.opengis.feature.AttributeType
  * @version 0.5
  * @module
  */
-final class CharacteristicTypeMap extends AbstractMap<String,AttributeType<?>> {
+final class CharacteristicTypeMap extends AbstractMap<String,DefaultAttributeType<?>> {
     /**
      * For sharing the same {@code CharacteristicTypeMap} instances among the attribute types
      * having the same characteristics.
      */
     @SuppressWarnings("unchecked")
-    private static final WeakValueHashMap<AttributeType<?>[],CharacteristicTypeMap> SHARED =
-            new WeakValueHashMap<AttributeType<?>[],CharacteristicTypeMap>((Class) AttributeType[].class);
+    private static final WeakValueHashMap<DefaultAttributeType<?>[],CharacteristicTypeMap> SHARED =
+            new WeakValueHashMap<DefaultAttributeType<?>[],CharacteristicTypeMap>((Class) DefaultAttributeType[].class);
 
     /*
-     * This class has intentionally no reference to the AttributeType for which we are providing characteristics.
+     * This class has intentionally no reference to the DefaultAttributeType for which we are providing characteristics.
      * This allows us to use the same CharacteristicTypeMap instance for various attribute types having the same
      * characteristic (e.g. many measurements may have an "accuracy" characteristic).
      */
@@ -67,7 +64,7 @@ final class CharacteristicTypeMap extend
      * Characteristics of an other attribute type (the {@code source} attribute given to the constructor).
      * This array shall not be modified.
      */
-    final AttributeType<?>[] characterizedBy;
+    final DefaultAttributeType<?>[] characterizedBy;
 
     /**
      * The names of attribute types listed in the {@link #characterizedBy} array,
@@ -86,7 +83,7 @@ final class CharacteristicTypeMap extend
      * @return A map for this given characteristics.
      * @throws IllegalArgumentException if two characteristics have the same name.
      */
-    static CharacteristicTypeMap create(final AttributeType<?> source, final AttributeType<?>[] characterizedBy) {
+    static CharacteristicTypeMap create(final DefaultAttributeType<?> source, final DefaultAttributeType<?>[] characterizedBy) {
         CharacteristicTypeMap map;
         synchronized (SHARED) {
             map = SHARED.get(characterizedBy);
@@ -108,12 +105,12 @@ final class CharacteristicTypeMap extend
      * @param  characterizedBy Characteristics of {@code source}. Should not be empty.
      * @throws IllegalArgumentException if two characteristics have the same name.
      */
-    private CharacteristicTypeMap(final AttributeType<?> source, final AttributeType<?>[] characterizedBy) {
+    private CharacteristicTypeMap(final DefaultAttributeType<?> source, final DefaultAttributeType<?>[] characterizedBy) {
         this.characterizedBy = characterizedBy;
         int index = 0;
         final Map<String,Integer> indices = new HashMap<String,Integer>(Containers.hashMapCapacity(characterizedBy.length));
         for (int i=0; i<characterizedBy.length; i++) {
-            final AttributeType<?> attribute = characterizedBy[i];
+            final DefaultAttributeType<?> attribute = characterizedBy[i];
             ensureNonNullElement("characterizedBy", i, attribute);
             final String name = AbstractIdentifiedType.toString(attribute.getName(), source, "characterizedBy", i);
             if (indices.put(name, index++) != null) {
@@ -144,7 +141,7 @@ final class CharacteristicTypeMap extend
      */
     @Override
     public boolean containsValue(final Object key) {
-        for (final AttributeType<?> type : characterizedBy) {
+        for (final DefaultAttributeType<?> type : characterizedBy) {
             if (type.equals(key)) {
                 return true;
             }
@@ -156,7 +153,7 @@ final class CharacteristicTypeMap extend
      * Returns the attribute characteristic for the given name, or {@code null} if none.
      */
     @Override
-    public AttributeType<?> get(final Object key) {
+    public DefaultAttributeType<?> get(final Object key) {
         final Integer index = indices.get(key);
         return (index != null) ? characterizedBy[index] : null;
     }
@@ -166,13 +163,13 @@ final class CharacteristicTypeMap extend
      * This is not the iterator returned by public API like {@code Map.entrySet().iterator()}.
      */
     @Override
-    protected EntryIterator<String, AttributeType<?>> entryIterator() {
-        return new EntryIterator<String, AttributeType<?>>() {
+    protected EntryIterator<String, DefaultAttributeType<?>> entryIterator() {
+        return new EntryIterator<String, DefaultAttributeType<?>>() {
             /** Index of the next element to return in the iteration. */
             private int index;
 
             /** Value of current entry. */
-            private AttributeType<?> value;
+            private DefaultAttributeType<?> value;
 
             /**
              * Returns {@code true} if there is more entries in the iteration.
@@ -198,7 +195,7 @@ final class CharacteristicTypeMap extend
              * Returns the attribute characteristic contained in this entry.
              */
             @Override
-            protected AttributeType<?> getValue() {
+            protected DefaultAttributeType<?> getValue() {
                 return value;
             }
         };

Modified: sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultAssociationRole.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultAssociationRole.java?rev=1640352&r1=1640351&r2=1640352&view=diff
==============================================================================
--- sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultAssociationRole.java [UTF-8] (original)
+++ sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultAssociationRole.java [UTF-8] Tue Nov 18 14:44:11 2014
@@ -382,6 +382,17 @@ public class DefaultAssociationRole exte
     }
 
     /**
+     * Creates a new association instance of this role.
+     *
+     * @return A new association instance.
+     *
+     * @see AbstractAssociation#create(FeatureAssociationRole)
+     */
+    public AbstractAssociation newInstance() {
+        return AbstractAssociation.create(this);
+    }
+
+    /**
      * Returns a hash code value for this association role.
      *
      * @return {@inheritDoc}

Modified: sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultAttributeType.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultAttributeType.java?rev=1640352&r1=1640351&r2=1640352&view=diff
==============================================================================
--- sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultAttributeType.java [UTF-8] (original)
+++ sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultAttributeType.java [UTF-8] Tue Nov 18 14:44:11 2014
@@ -17,6 +17,11 @@
 package org.apache.sis.feature;
 
 import java.util.Map;
+import java.util.Collections;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.IOException;
+import java.io.InvalidObjectException;
 import org.opengis.util.GenericName;
 import org.opengis.util.InternationalString;
 import org.apache.sis.util.Debug;
@@ -37,7 +42,9 @@ import org.apache.sis.internal.jdk7.Obje
  *
  * <div class="note"><b>Note:</b>
  * Compared to the Java language, {@code AttributeType} is equivalent to {@link java.lang.reflect.Field}
- * while {@code FeatureType} is equivalent to {@link Class}.</div>
+ * while {@code FeatureType} is equivalent to {@link Class}.
+ * Attribute characterization (discussed below) is similar to {@link java.lang.annotation.Annotation}.
+ * </div>
  *
  * <div class="warning"><b>Warning:</b>
  * This class is expected to implement a GeoAPI {@code AttributeType} interface in a future version.
@@ -56,6 +63,28 @@ import org.apache.sis.internal.jdk7.Obje
  *   <tr><td>Horizontal accuracy</td> <td>{@link org.opengis.metadata.quality.PositionalAccuracy}</td></tr>
  * </table>
  *
+ * {@section Attribute characterization}
+ * An {@code Attribute} can be characterized by other attributes. For example an attribute that carries a measurement
+ * (e.g. air temperature) may have another attribute that holds the measurement accuracy (e.g. ±0.1°C).
+ * The accuracy value is often constant for all instances of that attribute
+ * (e.g. for all temperature measurements in the same dataset), but this is not mandatory.
+ * Such accuracy could be stored as an ordinary, independent, attribute (like an other column in a table),
+ * but storing accuracy as a {@linkplain #characteristics() characteristic} of the measurement attribute instead
+ * provides the following advantages:
+ *
+ * <ul>
+ *   <li>The same characteristic name (e.g. “accuracy”) can be used for different attributes
+ *       (e.g. “temperature”, “humidity”, <i>etc.</i>) since all characteristics are local to their attribute.</li>
+ *   <li>A reference to an attribute gives also access to its characteristics. For example any method expecting
+ *       an {@code Attribute} argument, when given a measurement, can also get its accuracy in same time.</li>
+ *   <li>In the common case of a {@linkplain DefaultFeatureType#isSimple() simple feature} with characteristics
+ *       that are constants, declaring them as attribute characteristics allows to specify the constants only once.</li>
+ * </ul>
+ *
+ * Constant values of characteristics are given by their {@linkplain #getDefaultValue() default value}.
+ * It is still possible for any specific {@code Attribute} instance to specify their own value,
+ * but {@linkplain DefaultFeatureType#isSimple() simple feature} usually don't do that.
+ *
  * {@section Immutability and thread safety}
  * Instances of this class are immutable if all properties ({@link GenericName} and {@link InternationalString}
  * instances) and all arguments (e.g. {@code defaultValue}) given to the constructor are also immutable.
@@ -79,7 +108,7 @@ public class DefaultAttributeType<V> ext
     /**
      * For cross-version compatibility.
      */
-    private static final long serialVersionUID = 8215784957556648553L;
+    private static final long serialVersionUID = -817024213677735239L;
 
     /**
      * The class that describe the type of attribute values.
@@ -96,6 +125,14 @@ public class DefaultAttributeType<V> ext
     private final V defaultValue;
 
     /**
+     * Other attribute types that describes this attribute type, or {@code null} if none.
+     * This is used for attributes of attribute (e.g. accuracy of a position).
+     *
+     * @see #characteristics()
+     */
+    private transient CharacteristicTypeMap characteristics;
+
+    /**
      * Constructs an attribute type from the given properties. The identification map is given unchanged to
      * the {@linkplain AbstractIdentifiedType#AbstractIdentifiedType(Map) super-class constructor}.
      * The following table is a reminder of main (not all) recognized map entries:
@@ -129,21 +166,59 @@ public class DefaultAttributeType<V> ext
      *   </tr>
      * </table>
      *
-     * @param identification The name and other information to be given to this attribute type.
-     * @param valueClass     The type of attribute values.
-     * @param minimumOccurs  The minimum number of occurrences of the attribute within its containing entity.
-     * @param maximumOccurs  The maximum number of occurrences of the attribute within its containing entity,
-     *                       or {@link Integer#MAX_VALUE} if there is no restriction.
-     * @param defaultValue   The default value for the attribute, or {@code null} if none.
+     * @param identification  The name and other information to be given to this attribute type.
+     * @param valueClass      The type of attribute values.
+     * @param minimumOccurs   The minimum number of occurrences of the attribute within its containing entity.
+     * @param maximumOccurs   The maximum number of occurrences of the attribute within its containing entity,
+     *                        or {@link Integer#MAX_VALUE} if there is no restriction.
+     * @param defaultValue    The default value for the attribute, or {@code null} if none.
+     * @param characterizedBy Other attribute types that describes this attribute type (can be {@code null} for none).
+     *                        For example if this new {@code DefaultAttributeType} describes a measurement,
+     *                        then {@code characterizedBy} could holds the measurement accuracy.
+     *                        See "<cite>Attribute characterization</cite>" in class Javadoc for more information.
      */
     public DefaultAttributeType(final Map<String,?> identification, final Class<V> valueClass,
-            final int minimumOccurs, final int maximumOccurs, final V defaultValue)
+            final int minimumOccurs, final int maximumOccurs, final V defaultValue,
+            final DefaultAttributeType<?>... characterizedBy)
     {
         super(identification, minimumOccurs, maximumOccurs);
         ensureNonNull("valueClass",   valueClass);
         ensureCanCast("defaultValue", valueClass, defaultValue);
-        this.valueClass   = valueClass;
-        this.defaultValue = Numerics.cached(defaultValue);
+        this.valueClass      = valueClass;
+        this.defaultValue    = Numerics.cached(defaultValue);
+        if (characterizedBy != null && characterizedBy.length != 0) {
+            characteristics = CharacteristicTypeMap.create(this, characterizedBy.clone());
+        }
+    }
+
+    /**
+     * Invoked on serialization for saving the {@link #characteristics} field.
+     *
+     * @param  out The output stream where to serialize this attribute type.
+     * @throws IOException If an I/O error occurred while writing.
+     */
+    private void writeObject(final ObjectOutputStream out) throws IOException {
+        out.defaultWriteObject();
+        out.writeObject(characteristics != null ? characteristics.characterizedBy : null);
+    }
+
+    /**
+     * Invoked on deserialization for restoring the {@link #characteristics} field.
+     *
+     * @param  in The input stream from which to deserialize an attribute type.
+     * @throws IOException If an I/O error occurred while reading or if the stream contains invalid data.
+     * @throws ClassNotFoundException If the class serialized on the stream is not on the classpath.
+     */
+    private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException {
+        in.defaultReadObject();
+        try {
+            final DefaultAttributeType<?>[] characterizedBy = (DefaultAttributeType<?>[]) in.readObject();
+            if (characterizedBy != null) {
+                characteristics = CharacteristicTypeMap.create(this, characterizedBy);
+            }
+        } catch (RuntimeException e) { // At least ClassCastException, NullPointerException and IllegalArgumentException.
+            throw (IOException) new InvalidObjectException(e.getMessage()).initCause(e);
+        }
     }
 
     /**
@@ -207,13 +282,44 @@ public class DefaultAttributeType<V> ext
     }
 
     /**
+     * Other attribute types that describes this attribute type.
+     * See "<cite>Attribute characterization</cite>" in class Javadoc for more information.
+     *
+     * <div class="note"><b>Example:</b>
+     * An attribute that carries a measurement (e.g. air temperature) may have another attribute that holds the
+     * measurement accuracy. The accuracy is often constant for all measurements in a dataset, but not necessarily.
+     * If the accuracy is a constant, then the characteristics {@linkplain #getDefaultValue() default value}
+     * shall hold that constant.
+     * </div>
+     *
+     * @return Other attribute types that describes this attribute type, or an empty set if none.
+     *
+     * @see AbstractAttribute#characteristics()
+     */
+    public Map<String,DefaultAttributeType<?>> characteristics() {
+        return (characteristics != null) ? characteristics : Collections.<String,DefaultAttributeType<?>>emptyMap();
+    }
+
+    /**
+     * Creates a new attribute instance of this type initialized to the {@linkplain #getDefaultValue() default value}.
+     *
+     * @return A new attribute instance.
+     *
+     * @see AbstractAttribute#create(DefaultAttributeType)
+     */
+    public AbstractAttribute<V> newInstance() {
+        return AbstractAttribute.create(this);
+    }
+
+    /**
      * Returns a hash code value for this attribute type.
      *
      * @return {@inheritDoc}
      */
     @Override
     public int hashCode() {
-        return super.hashCode() + valueClass.hashCode() + Objects.hashCode(defaultValue);
+        return super.hashCode() + valueClass.hashCode() + Objects.hashCode(defaultValue)
+               + Objects.hashCode(characteristics);
     }
 
     /**
@@ -229,7 +335,8 @@ public class DefaultAttributeType<V> ext
         if (super.equals(obj)) {
             final DefaultAttributeType<?> that = (DefaultAttributeType<?>) obj;
             return valueClass == that.valueClass &&
-                   Objects.equals(defaultValue, that.defaultValue);
+                   Objects.equals(defaultValue, that.defaultValue) &&
+                   Objects.equals(characteristics, that.characteristics);
         }
         return false;
     }

Modified: sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultFeatureType.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultFeatureType.java?rev=1640352&r1=1640351&r2=1640352&view=diff
==============================================================================
--- sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultFeatureType.java [UTF-8] (original)
+++ sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultFeatureType.java [UTF-8] Tue Nov 18 14:44:11 2014
@@ -357,7 +357,7 @@ public class DefaultFeatureType extends 
         int index = -1;
         for (final AbstractIdentifiedType property : source.getProperties(false)) {
             ArgumentChecks.ensureNonNullElement("properties", ++index, property);
-            final String name = toString(property.getName(), source, index);
+            final String name = toString(property.getName(), source, "properties", index);
             final AbstractIdentifiedType previous = byName.put(name, property);
             if (previous != null) {
                 if (!isAssignableIgnoreName(previous, property)) {
@@ -392,33 +392,6 @@ public class DefaultFeatureType extends 
     }
 
     /**
-     * Returns the string representation of the given name, making sure that the name is non-null
-     * and the string non-empty. This method is used for checking argument validity.
-     *
-     * <p>{@code this} shall be the instance in process of being created, not any other instance.</p>
-     *
-     * @param name   The name for which to get the string representation.
-     * @param source The feature which contains the property (typically {@code this}).
-     * @param index  Index of the property having the given name.
-     */
-    private String toString(final GenericName name, final DefaultFeatureType source, final int index) {
-        short key = Errors.Keys.MissingValueForProperty_1;
-        if (name != null) {
-            final String s = name.toString();
-            if (!s.isEmpty()) {
-                return s;
-            }
-            key = Errors.Keys.EmptyProperty_1;
-        }
-        final StringBuilder b = new StringBuilder(30);
-        if (source != this) {
-            b.append(source.getName()).append('.');
-        }
-        throw new IllegalArgumentException(Errors.format(key,
-                b.append("properties[").append(index).append("].name").toString()));
-    }
-
-    /**
      * If an associated feature type is a placeholder for a {@code FeatureType} to be defined later,
      * replaces the placeholder by the actual instance if available. Otherwise do nothing.
      *

Modified: sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/Features.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/Features.java?rev=1640352&r1=1640351&r2=1640352&view=diff
==============================================================================
--- sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/Features.java [UTF-8] (original)
+++ sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/Features.java [UTF-8] Tue Nov 18 14:44:11 2014
@@ -21,7 +21,7 @@ import org.apache.sis.util.resources.Err
 
 
 /**
- * Static methods working on features.
+ * Static methods working on features or attributes.
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.5

Modified: sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/FieldType.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/FieldType.java?rev=1640352&r1=1640351&r2=1640352&view=diff
==============================================================================
--- sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/FieldType.java [UTF-8] (original)
+++ sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/FieldType.java [UTF-8] Tue Nov 18 14:44:11 2014
@@ -157,7 +157,7 @@ abstract class FieldType extends Abstrac
      * @param valueType The name of value class (attribute), or the feature type name (association).
      * @param values    The actual values.
      */
-    static String toString(final String className, final AbstractIdentifiedType type,
+    static StringBuilder toString(final String className, final AbstractIdentifiedType type,
             final Object valueType, final Iterator<?> values)
     {
         final StringBuilder buffer = toString(className, type, valueType);
@@ -177,6 +177,6 @@ abstract class FieldType extends Abstrac
                 buffer.append('}');
             }
         }
-        return buffer.toString();
+        return buffer;
     }
 }

Modified: sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/MultiValuedAssociation.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/MultiValuedAssociation.java?rev=1640352&r1=1640351&r2=1640352&view=diff
==============================================================================
--- sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/MultiValuedAssociation.java [UTF-8] (original)
+++ sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/MultiValuedAssociation.java [UTF-8] Tue Nov 18 14:44:11 2014
@@ -44,7 +44,7 @@ import org.apache.sis.util.resources.Err
  *
  * @see DefaultAssociationRole
  */
-final class MultiValuedAssociation extends AbstractAssociation implements Cloneable {
+final class MultiValuedAssociation extends AbstractAssociation {
     /**
      * For cross-version compatibility.
      */
@@ -139,14 +139,11 @@ final class MultiValuedAssociation exten
 
     /**
      * Returns a copy of this association.
-     * The default implementation returns a <em>shallow</em> copy:
+     * This implementation returns a <em>shallow</em> copy:
      * the association {@linkplain #getValues() values} are <strong>not</strong> cloned.
-     * However subclasses may choose to do otherwise.
      *
      * @return A clone of this association.
      * @throws CloneNotSupportedException if this association can not be cloned.
-     *         The default implementation never throw this exception. However subclasses may throw it,
-     *         for example on attempt to clone the association values.
      */
     @Override
     @SuppressWarnings("unchecked")

Modified: sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/MultiValuedAttribute.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/MultiValuedAttribute.java?rev=1640352&r1=1640351&r2=1640352&view=diff
==============================================================================
--- sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/MultiValuedAttribute.java [UTF-8] (original)
+++ sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/MultiValuedAttribute.java [UTF-8] Tue Nov 18 14:44:11 2014
@@ -47,7 +47,7 @@ import org.apache.sis.util.resources.Err
  *
  * @see DefaultAttributeType
  */
-final class MultiValuedAttribute<V> extends AbstractAttribute<V> implements Cloneable {
+final class MultiValuedAttribute<V> extends AbstractAttribute<V> {
     /**
      * For cross-version compatibility.
      */
@@ -147,18 +147,15 @@ final class MultiValuedAttribute<V> exte
 
     /**
      * Returns a copy of this attribute.
-     * The default implementation returns a <em>shallow</em> copy:
+     * This implementation returns a <em>shallow</em> copy:
      * the attribute {@linkplain #getValues() values} are <strong>not</strong> cloned.
-     * However subclasses may choose to do otherwise.
      *
      * @return A clone of this attribute.
      * @throws CloneNotSupportedException if this attribute can not be cloned.
-     *         The default implementation never throw this exception. However subclasses may throw it,
-     *         for example on attempt to clone the attribute values.
      */
     @Override
     @SuppressWarnings("unchecked")
-    public MultiValuedAttribute<V> clone() throws CloneNotSupportedException {
+    public AbstractAttribute<V> clone() throws CloneNotSupportedException {
         final MultiValuedAttribute<V> clone = (MultiValuedAttribute<V>) super.clone();
         clone.values = (CheckedArrayList<V>) clone.values.clone();
         return clone;
@@ -171,7 +168,7 @@ final class MultiValuedAttribute<V> exte
      */
     @Override
     public int hashCode() {
-        return type.hashCode() + values.hashCode();
+        return type.hashCode() + values.hashCode() + characteristicsReadOnly().hashCode();
     }
 
     /**
@@ -186,7 +183,8 @@ final class MultiValuedAttribute<V> exte
         }
         if (obj instanceof MultiValuedAttribute<?>) {
             final MultiValuedAttribute<?> that = (MultiValuedAttribute<?>) obj;
-            return type.equals(that.type) && values.equals(that.values);
+            return type.equals(that.type) && values.equals(that.values) &&
+                   characteristicsReadOnly().equals(that.characteristicsReadOnly());
         }
         return false;
     }

Modified: sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/PropertySingleton.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/PropertySingleton.java?rev=1640352&r1=1640351&r2=1640352&view=diff
==============================================================================
--- sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/PropertySingleton.java [UTF-8] (original)
+++ sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/PropertySingleton.java [UTF-8] Tue Nov 18 14:44:11 2014
@@ -16,6 +16,7 @@
  */
 package org.apache.sis.feature;
 
+import java.util.List;
 import java.util.AbstractList;
 import java.util.Iterator;
 import java.util.NoSuchElementException;
@@ -186,6 +187,37 @@ final class PropertySingleton<V> extends
     }
 
     /**
+     * Same contract than {@link AbstractList}, just slightly more efficient for this particular class.
+     */
+    @Override
+    public int hashCode() {
+        final V element = property.getValue();
+        final int hashCode = (element != null) ? 31 + element.hashCode() : 1;
+        assert hashCode == super.hashCode() : hashCode;
+        return hashCode;
+    }
+
+    /**
+     * Same contract than {@link AbstractList}, just slightly more efficient for this particular class.
+     */
+    @Override
+    public boolean equals(final Object other) {
+        if (other == this) {
+            return true;
+        }
+        if (other instanceof List<?>) {
+            final V element = property.getValue();
+            if (element == null) {
+                return ((List<?>) other).isEmpty();
+            } else {
+                final Iterator<?> it = ((List<?>) other).iterator();
+                return it.hasNext() && element.equals(it.next()) && !it.hasNext();
+            }
+        }
+        return false;
+    }
+
+    /**
      * Returns an iterator over the unique element in this list.
      */
     @Override

Modified: sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/SingletonAssociation.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/SingletonAssociation.java?rev=1640352&r1=1640351&r2=1640352&view=diff
==============================================================================
--- sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/SingletonAssociation.java [UTF-8] (original)
+++ sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/SingletonAssociation.java [UTF-8] Tue Nov 18 14:44:11 2014
@@ -39,7 +39,7 @@ import org.apache.sis.internal.jdk7.Obje
  *
  * @see DefaultAssociationRole
  */
-final class SingletonAssociation extends AbstractAssociation implements Cloneable {
+final class SingletonAssociation extends AbstractAssociation {
     /**
      * For cross-version compatibility.
      */
@@ -100,21 +100,6 @@ final class SingletonAssociation extends
     }
 
     /**
-     * Returns a copy of this association.
-     * The default implementation returns a <em>shallow</em> copy:
-     * the association {@linkplain #getValue() value} is <strong>not</strong> cloned.
-     * However subclasses may choose to do otherwise.
-     *
-     * @return A clone of this association.
-     * @throws CloneNotSupportedException if this association can not be cloned.
-     *         The default implementation never throw this exception. However subclasses may throw it.
-     */
-    @Override
-    public SingletonAssociation clone() throws CloneNotSupportedException {
-        return (SingletonAssociation) super.clone();
-    }
-
-    /**
      * Returns a hash code value for this association.
      *
      * @return A hash code value.

Modified: sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/SingletonAttribute.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/SingletonAttribute.java?rev=1640352&r1=1640351&r2=1640352&view=diff
==============================================================================
--- sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/SingletonAttribute.java [UTF-8] (original)
+++ sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/SingletonAttribute.java [UTF-8] Tue Nov 18 14:44:11 2014
@@ -42,7 +42,7 @@ import org.apache.sis.internal.jdk7.Obje
  *
  * @see DefaultAttributeType
  */
-final class SingletonAttribute<V> extends AbstractAttribute<V> implements Cloneable {
+final class SingletonAttribute<V> extends AbstractAttribute<V> {
     /**
      * For cross-version compatibility.
      */
@@ -99,30 +99,13 @@ final class SingletonAttribute<V> extend
     }
 
     /**
-     * Returns a copy of this attribute.
-     * The default implementation returns a <em>shallow</em> copy:
-     * the attribute {@linkplain #getValue() value} is <strong>not</strong> cloned.
-     * However subclasses may choose to do otherwise.
-     *
-     * @return A clone of this attribute.
-     * @throws CloneNotSupportedException if this attribute can not be cloned.
-     *         The default implementation never throw this exception. However subclasses may throw it,
-     *         for example on attempt to clone the attribute value.
-     */
-    @Override
-    @SuppressWarnings("unchecked")
-    public SingletonAttribute<V> clone() throws CloneNotSupportedException {
-        return (SingletonAttribute<V>) super.clone();
-    }
-
-    /**
      * Returns a hash code value for this attribute.
      *
      * @return A hash code value.
      */
     @Override
     public int hashCode() {
-        return type.hashCode() + Objects.hashCode(value);
+        return type.hashCode() + Objects.hashCode(value) + characteristicsReadOnly().hashCode();
     }
 
     /**
@@ -137,7 +120,8 @@ final class SingletonAttribute<V> extend
         }
         if (obj instanceof SingletonAttribute<?>) {
             final SingletonAttribute<?> that = (SingletonAttribute<?>) obj;
-            return type.equals(that.type) && Objects.equals(value, that.value);
+            return type.equals(that.type) && Objects.equals(value, that.value) &&
+                   characteristicsReadOnly().equals(that.characteristicsReadOnly());
         }
         return false;
     }

Modified: sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/SparseFeature.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/SparseFeature.java?rev=1640352&r1=1640351&r2=1640352&view=diff
==============================================================================
--- sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/SparseFeature.java [UTF-8] (original)
+++ sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/SparseFeature.java [UTF-8] Tue Nov 18 14:44:11 2014
@@ -102,7 +102,7 @@ final class SparseFeature extends Abstra
         if (valuesKind != PROPERTIES) {
             if (!properties.isEmpty()) { // The map is typically empty when this method is first invoked.
                 if (valuesKind != VALUES) {
-                    throw new CorruptedObjectException(String.valueOf(getName()));
+                    throw new CorruptedObjectException(getName());
                 }
                 valuesKind = CORRUPTED;
                 for (final Map.Entry<String, Object> entry : properties.entrySet()) {
@@ -182,7 +182,7 @@ final class SparseFeature extends Abstra
             } else if (valuesKind == PROPERTIES) {
                 throw unsupportedPropertyType(((Property) element).getName());
             } else {
-                throw new CorruptedObjectException(String.valueOf(getName()));
+                throw new CorruptedObjectException(getName());
             }
         } else if (properties.containsKey(name)) {
             return null; // Null has been explicitely set.
@@ -222,7 +222,7 @@ final class SparseFeature extends Abstra
         } else if (valuesKind == PROPERTIES) {
             setPropertyValue(getPropertyInstance(name), value);
         } else {
-            throw new CorruptedObjectException(String.valueOf(getName()));
+            throw new CorruptedObjectException(getName());
         }
     }
 

Propchange: sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/SparseFeature.java
------------------------------------------------------------------------------
  Merged /sis/branches/JDK6/core/sis-feature/src/main/java/org/apache/sis/feature/SparseFeature.java:r1598750-1640308
  Merged /sis/branches/JDK7/core/sis-feature/src/main/java/org/apache/sis/feature/SparseFeature.java:r1598749-1640304
  Merged /sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/SparseFeature.java:r1598745-1640283

Copied: sis/trunk/core/sis-feature/src/test/java/org/apache/sis/feature/CharacteristicMapTest.java (from r1640308, sis/branches/JDK6/core/sis-feature/src/test/java/org/apache/sis/feature/CharacteristicMapTest.java)
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-feature/src/test/java/org/apache/sis/feature/CharacteristicMapTest.java?p2=sis/trunk/core/sis-feature/src/test/java/org/apache/sis/feature/CharacteristicMapTest.java&p1=sis/branches/JDK6/core/sis-feature/src/test/java/org/apache/sis/feature/CharacteristicMapTest.java&r1=1640308&r2=1640352&rev=1640352&view=diff
==============================================================================
--- sis/branches/JDK6/core/sis-feature/src/test/java/org/apache/sis/feature/CharacteristicMapTest.java [UTF-8] (original)
+++ sis/trunk/core/sis-feature/src/test/java/org/apache/sis/feature/CharacteristicMapTest.java [UTF-8] Tue Nov 18 14:44:11 2014
@@ -26,9 +26,6 @@ import org.junit.Test;
 
 import static org.apache.sis.test.Assert.*;
 
-// Branch-dependent imports
-import org.opengis.feature.Attribute;
-
 
 /**
  * Tests {@link CharacteristicMap} indirectly, through {@link AbstractAttribute} construction.
@@ -65,10 +62,10 @@ public final strictfp class Characterist
      */
     @Test
     public void testPut() {
-        final AbstractAttribute<?>     temperature     = temperature();
-        final AbstractAttribute<?>     units           = create(temperature, "units");
-        final AbstractAttribute<?>     accuracy        = create(temperature, "accuracy");
-        final Map<String,Attribute<?>> characteristics = temperature.characteristics();
+        final AbstractAttribute<?> temperature = temperature();
+        final AbstractAttribute<?> units       = create(temperature, "units");
+        final AbstractAttribute<?> accuracy    = create(temperature, "accuracy");
+        final Map<String,AbstractAttribute<?>> characteristics = temperature.characteristics();
         /*
          * Verify that the map is initially empty.
          */
@@ -153,11 +150,11 @@ public final strictfp class Characterist
     @Test
     @DependsOnMethod("testPut")
     public void testAddValue() {
-        final AbstractAttribute<?>     temperature     = temperature();
-        final AbstractAttribute<?>     units           = create(temperature, "units");
-        final AbstractAttribute<?>     accuracy        = create(temperature, "accuracy");
-        final Map<String,Attribute<?>> characteristics = temperature.characteristics();
-        final Collection<Attribute<?>> values          = characteristics.values();
+        final AbstractAttribute<?> temperature = temperature();
+        final AbstractAttribute<?> units       = create(temperature, "units");
+        final AbstractAttribute<?> accuracy    = create(temperature, "accuracy");
+        final Map<String,AbstractAttribute<?>> characteristics = temperature.characteristics();
+        final Collection<AbstractAttribute<?>> values          = characteristics.values();
         /*
          * Verify that the collection is initially empty.
          */
@@ -211,10 +208,10 @@ public final strictfp class Characterist
     @Test
     @DependsOnMethod("testPut")
     public void testAddKey() {
-        final Attribute<?> units, accuracy;
-        final AbstractAttribute<?>     temperature     = temperature();
-        final Map<String,Attribute<?>> characteristics = temperature.characteristics();
-        final Collection<String>       keys            = characteristics.keySet();
+        final AbstractAttribute<?> units, accuracy;
+        final AbstractAttribute<?> temperature = temperature();
+        final Map<String,AbstractAttribute<?>> characteristics = temperature.characteristics();
+        final Collection<String> keys = characteristics.keySet();
         /*
          * Verify that the collection is initially empty.
          */
@@ -272,14 +269,14 @@ public final strictfp class Characterist
      * @param accuracy        The second expected value in iteration order.
      * @param characteristics The map to verify.
      */
-    private static void assertEntriesEqual(final Attribute<?> units, final Attribute<?> accuracy,
-            final Map<String,Attribute<?>> characteristics)
+    private static void assertEntriesEqual(final AbstractAttribute<?> units, final AbstractAttribute<?> accuracy,
+            final Map<String,AbstractAttribute<?>> characteristics)
     {
         assertArrayEquals("keySet", new String[] {"accuracy", "units"}, characteristics.keySet().toArray());
         assertArrayEquals("values", new Object[] { accuracy ,  units }, characteristics.values().toArray());
         assertArrayEquals("entrySet", new Object[] {
-                new SimpleEntry<String,Attribute<?>>("accuracy", accuracy),
-                new SimpleEntry<String,Attribute<?>>("units",    units)
+                new SimpleEntry<String,AbstractAttribute<?>>("accuracy", accuracy),
+                new SimpleEntry<String,AbstractAttribute<?>>("units",    units)
             }, characteristics.entrySet().toArray());
     }
 
@@ -292,7 +289,7 @@ public final strictfp class Characterist
      */
     private static void setAccuracy(final AbstractAttribute<Float> temperature, final boolean isFirstTime, final float value) {
         assertEquals("keySet.add", isFirstTime, temperature.characteristics().keySet().add("accuracy"));
-        final Attribute<Float> accuracy = Features.cast(temperature.characteristics().get("accuracy"), Float.class);
+        final AbstractAttribute<Float> accuracy = Features.cast(temperature.characteristics().get("accuracy"), Float.class);
         accuracy.setValue(value);
     }
 

Copied: sis/trunk/core/sis-feature/src/test/java/org/apache/sis/feature/CharacteristicTypeMapTest.java (from r1640308, sis/branches/JDK6/core/sis-feature/src/test/java/org/apache/sis/feature/CharacteristicTypeMapTest.java)
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-feature/src/test/java/org/apache/sis/feature/CharacteristicTypeMapTest.java?p2=sis/trunk/core/sis-feature/src/test/java/org/apache/sis/feature/CharacteristicTypeMapTest.java&p1=sis/branches/JDK6/core/sis-feature/src/test/java/org/apache/sis/feature/CharacteristicTypeMapTest.java&r1=1640308&r2=1640352&rev=1640352&view=diff
==============================================================================
--- sis/branches/JDK6/core/sis-feature/src/test/java/org/apache/sis/feature/CharacteristicTypeMapTest.java [UTF-8] (original)
+++ sis/trunk/core/sis-feature/src/test/java/org/apache/sis/feature/CharacteristicTypeMapTest.java [UTF-8] Tue Nov 18 14:44:11 2014
@@ -26,9 +26,6 @@ import static java.util.Collections.sing
 import static org.apache.sis.feature.DefaultAssociationRole.NAME_KEY;
 import static org.apache.sis.test.Assert.*;
 
-// Branch-dependent imports
-import org.opengis.feature.AttributeType;
-
 
 /**
  * Tests {@link CharacteristicTypeMap} indirectly, through {@link DefaultAttributeType} construction.
@@ -74,9 +71,9 @@ public final strictfp class Characterist
      */
     @Test
     public void testMapMethods() {
-        final AttributeType<?> units, accuracy;
+        final DefaultAttributeType<?> units, accuracy;
         final DefaultAttributeType<Float> temperature = temperature();
-        final Map<String, AttributeType<?>> characteristics = temperature.characteristics();
+        final Map<String, DefaultAttributeType<?>> characteristics = temperature.characteristics();
 
         assertFalse  ("isEmpty",        characteristics.isEmpty());
         assertEquals ("size", 2,        characteristics.size());
@@ -94,8 +91,8 @@ public final strictfp class Characterist
         assertArrayEquals("keySet", new String[] {"accuracy", "units"}, characteristics.keySet().toArray());
         assertArrayEquals("values", new Object[] { accuracy ,  units }, characteristics.values().toArray());
         assertArrayEquals("entrySet", new Object[] {
-                new SimpleEntry<String,AttributeType<?>>("accuracy", accuracy),
-                new SimpleEntry<String,AttributeType<?>>("units",    units)
+                new SimpleEntry<String,DefaultAttributeType<?>>("accuracy", accuracy),
+                new SimpleEntry<String,DefaultAttributeType<?>>("units",    units)
             }, characteristics.entrySet().toArray());
     }
 

Modified: sis/trunk/core/sis-feature/src/test/java/org/apache/sis/feature/DefaultAttributeTypeTest.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-feature/src/test/java/org/apache/sis/feature/DefaultAttributeTypeTest.java?rev=1640352&r1=1640351&r2=1640352&view=diff
==============================================================================
--- sis/trunk/core/sis-feature/src/test/java/org/apache/sis/feature/DefaultAttributeTypeTest.java [UTF-8] (original)
+++ sis/trunk/core/sis-feature/src/test/java/org/apache/sis/feature/DefaultAttributeTypeTest.java [UTF-8] Tue Nov 18 14:44:11 2014
@@ -32,6 +32,8 @@ import static org.apache.sis.test.Assert
 
 /**
  * Tests {@link DefaultAttributeType}.
+ * This class does not test {@link DefaultAttributeType#characteristics()}.
+ * Characteristics are tested by {@link CharacteristicTypeMapTest} instead.
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.5

Modified: sis/trunk/core/sis-feature/src/test/java/org/apache/sis/feature/MultiValuedAttributeTest.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-feature/src/test/java/org/apache/sis/feature/MultiValuedAttributeTest.java?rev=1640352&r1=1640351&r2=1640352&view=diff
==============================================================================
--- sis/trunk/core/sis-feature/src/test/java/org/apache/sis/feature/MultiValuedAttributeTest.java [UTF-8] (original)
+++ sis/trunk/core/sis-feature/src/test/java/org/apache/sis/feature/MultiValuedAttributeTest.java [UTF-8] Tue Nov 18 14:44:11 2014
@@ -140,7 +140,7 @@ public final strictfp class MultiValuedA
     @DependsOnMethod("testEquals")
     public void testClone() throws CloneNotSupportedException {
         final MultiValuedAttribute<Integer> a1 = population();
-        final MultiValuedAttribute<Integer> a2 = a1.clone();
+        final    AbstractAttribute<Integer> a2 = a1.clone();
         assertNotSame(a1, a2);
         SingletonAttributeTest.testEquals(a1, a2);
     }

Modified: sis/trunk/core/sis-feature/src/test/java/org/apache/sis/feature/SingletonAttributeTest.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-feature/src/test/java/org/apache/sis/feature/SingletonAttributeTest.java?rev=1640352&r1=1640351&r2=1640352&view=diff
==============================================================================
--- sis/trunk/core/sis-feature/src/test/java/org/apache/sis/feature/SingletonAttributeTest.java [UTF-8] (original)
+++ sis/trunk/core/sis-feature/src/test/java/org/apache/sis/feature/SingletonAttributeTest.java [UTF-8] Tue Nov 18 14:44:11 2014
@@ -157,7 +157,7 @@ public final strictfp class SingletonAtt
     @DependsOnMethod("testEquals")
     public void testClone() throws CloneNotSupportedException {
         final SingletonAttribute<Integer> a1 = population();
-        final SingletonAttribute<Integer> a2 = a1.clone();
+        final  AbstractAttribute<Integer> a2 = a1.clone();
         assertNotSame(a1, a2);
         testEquals(a1, a2);
     }

Modified: sis/trunk/core/sis-feature/src/test/java/org/apache/sis/test/suite/FeatureTestSuite.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-feature/src/test/java/org/apache/sis/test/suite/FeatureTestSuite.java?rev=1640352&r1=1640351&r2=1640352&view=diff
==============================================================================
--- sis/trunk/core/sis-feature/src/test/java/org/apache/sis/test/suite/FeatureTestSuite.java [UTF-8] (original)
+++ sis/trunk/core/sis-feature/src/test/java/org/apache/sis/test/suite/FeatureTestSuite.java [UTF-8] Tue Nov 18 14:44:11 2014
@@ -31,6 +31,8 @@ import org.junit.BeforeClass;
  */
 @Suite.SuiteClasses({
     org.apache.sis.feature.DefaultAttributeTypeTest.class,
+    org.apache.sis.feature.CharacteristicTypeMapTest.class,
+    org.apache.sis.feature.CharacteristicMapTest.class,
     org.apache.sis.feature.DefaultFeatureTypeTest.class,
     org.apache.sis.feature.PropertySingletonTest.class,
     org.apache.sis.feature.SingletonAttributeTest.class,



Mime
View raw message