sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1596871 - in /sis/branches/JDK8/core: sis-feature/src/main/java/org/apache/sis/feature/ sis-feature/src/test/java/org/apache/sis/feature/ sis-feature/src/test/java/org/apache/sis/test/suite/ sis-referencing/src/main/java/org/apache/sis/par...
Date Thu, 22 May 2014 13:50:54 GMT
Author: desruisseaux
Date: Thu May 22 13:50:53 2014
New Revision: 1596871

URL: http://svn.apache.org/r1596871
Log:
Initial support of multi-valued attribute.

Added:
    sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractAttribute.java
      - copied, changed from r1596663, sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultAttribute.java
    sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/SingletonAttribute.java
      - copied, changed from r1596663, sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultAttribute.java
    sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/SingletonAttributeTest.java
      - copied, changed from r1596663, sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/DefaultAttributeTest.java
Removed:
    sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultAttribute.java
    sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/DefaultAttributeTest.java
Modified:
    sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractFeature.java
    sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultAssociation.java
    sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultAttributeType.java
    sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/DenseFeature.java
    sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/FeatureFormat.java
    sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/Features.java
    sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/FieldType.java
    sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/PropertySingleton.java
    sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/SparseFeature.java
    sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/package-info.java
    sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/CustomAttribute.java
    sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/DefaultOperationTest.java
    sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/DenseFeatureTest.java
    sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/FeatureTestCase.java
    sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/FeaturesTest.java
    sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/PropertySingletonTest.java
    sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/SparseFeatureTest.java
    sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/test/suite/FeatureTestSuite.java
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/parameter/ParameterValueList.java
    sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/util/Cloner.java
    sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java
    sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties
    sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties

Copied: sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractAttribute.java (from r1596663, sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultAttribute.java)
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractAttribute.java?p2=sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractAttribute.java&p1=sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultAttribute.java&r1=1596663&r2=1596871&rev=1596871&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultAttribute.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractAttribute.java [UTF-8] Thu May 22 13:50:53 2014
@@ -16,6 +16,8 @@
  */
 package org.apache.sis.feature;
 
+import java.util.Collection;
+import java.util.Iterator;
 import java.io.Serializable;
 import org.opengis.util.GenericName;
 import org.opengis.metadata.quality.DataQuality;
@@ -23,9 +25,7 @@ import org.opengis.metadata.maintenance.
 import org.apache.sis.util.Debug;
 import org.apache.sis.util.Classes;
 import org.apache.sis.util.ArgumentChecks;
-
-// Related to JDK7
-import java.util.Objects;
+import org.apache.sis.util.resources.Errors;
 
 
 /**
@@ -35,12 +35,17 @@ import java.util.Objects;
  * <ul>
  *   <li>A reference to an {@linkplain DefaultAttributeType attribute type}
  *       which define the base Java type and domain of valid values.</li>
- *   <li>A value.</li>
+ *   <li>A value, which may be a singleton ([0 … 1] cardinality) or multi-valued ([0 … ∞] cardinality).</li>
  * </ul>
  *
- * {@section Usage in multi-thread environment}
- * {@code DefaultAttribute} are <strong>not</strong> thread-safe.
- * Synchronization, if needed, shall be done externally by the caller.
+ * {@section Limitations}
+ * <ul>
+ *   <li><b>Multi-threading:</b> {@code AbstractAttribute} instances are <strong>not</strong> thread-safe.
+ *       Synchronization, if needed, shall be done externally by the caller.</li>
+ *   <li><b>Serialization:</b> serialized objects of this class are not guaranteed to be compatible with future
+ *       versions. Serialization should be used only for short term storage or RMI between applications running
+ *       the same SIS version.</li>
+ * </ul>
  *
  * @param <T> The type of attribute values.
  *
@@ -52,45 +57,25 @@ import java.util.Objects;
  *
  * @see DefaultAttributeType
  */
-public class DefaultAttribute<T> extends Property implements Cloneable, Serializable {
+public abstract class AbstractAttribute<T> extends Property implements Serializable {
     /**
      * For cross-version compatibility.
      */
-    private static final long serialVersionUID = -8103788797446754561L;
+    private static final long serialVersionUID = 7442739120526654676L;
 
     /**
      * Information about the attribute (base Java class, domain of values, <i>etc.</i>).
      */
-    private final DefaultAttributeType<T> type;
-
-    /**
-     * The attribute value.
-     */
-    private T value;
+    final DefaultAttributeType<T> type;
 
     /**
-     * Creates a new attribute of the given type initialized to the
-     * {@linkplain DefaultAttributeType#getDefaultValue() default value}.
+     * Creates a new attribute of the given type.
      *
      * @param type Information about the attribute (base Java class, domain of values, <i>etc.</i>).
      */
-    public DefaultAttribute(final DefaultAttributeType<T> type) {
-        ArgumentChecks.ensureNonNull("type", type);
-        this.type  = type;
-        this.value = type.getDefaultValue();
-    }
-
-    /**
-     * Creates a new attribute of the given type initialized to the given value.
-     * Note that a {@code null} value may not the same as the default value.
-     *
-     * @param type  Information about the attribute (base Java class, domain of values, <i>etc.</i>).
-     * @param value The initial value (may be null {@code null}).
-     */
-    public DefaultAttribute(final DefaultAttributeType<T> type, final Object value) {
+    public AbstractAttribute(final DefaultAttributeType<T> type) {
         ArgumentChecks.ensureNonNull("type", type);
-        this.type  = type;
-        this.value = type.getValueClass().cast(value);
+        this.type = type;
     }
 
     /**
@@ -117,18 +102,33 @@ public class DefaultAttribute<T> extends
     }
 
     /**
-     * Returns the attribute value.
+     * Returns the attribute value, or {@code null} if none. This convenience method can be invoked in
+     * the common case where the {@linkplain DefaultAttributeType#getMaximumOccurs() maximum number}
+     * of attribute values is restricted to 1 or 0.
      *
      * @return The attribute value (may be {@code null}).
+     * @throws IllegalStateException if this attribute contains more than one value.
      *
      * @see AbstractFeature#getPropertyValue(String)
      */
-    public T getValue() {
-        return value;
+    public abstract T getValue() throws IllegalStateException;
+
+    /**
+     * Returns all attribute values, or an empty collection if none.
+     * The returned collection is <cite>live</cite>: changes in the returned collection
+     * will be reflected immediately in this {@code Attribute} instance, and conversely.
+     *
+     * <p>The default implementation returns a collection which will delegate its work to
+     * {@link #getValue()} and {@link #setValue(Object)}.</p>
+     *
+     * @return The attribute values in a <cite>live</cite> collection.
+     */
+    public Collection<T> getValues() {
+        return new PropertySingleton<>(this);
     }
 
     /**
-     * Sets the attribute value.
+     * Sets the attribute value. All previous values are replaced by the given singleton.
      *
      * {@section Validation}
      * The amount of validation performed by this method is implementation dependent.
@@ -136,12 +136,31 @@ public class DefaultAttribute<T> extends
      * and also because some rules may be temporarily broken while constructing a feature.
      * A more exhaustive verification can be performed by invoking the {@link #quality()} method.
      *
-     * @param value The new value.
+     * @param value The new value, or {@code null} for removing all values from this attribute.
      *
      * @see AbstractFeature#setPropertyValue(String, Object)
      */
-    public void setValue(final T value) {
-        this.value = value;
+    public abstract void setValue(final T value);
+
+    /**
+     * Set the attribute values. All previous values are replaced by the given collection.
+     *
+     * <p>The default implementation ensures that the given collection contains at most one element,
+     * then delegates to {@link #setValue(Object)}.</p>
+     *
+     * @param values The new values.
+     */
+    public void setValues(final Collection<? extends T> values) {
+        T value = null;
+        ArgumentChecks.ensureNonNull("values", values);
+        final Iterator<? extends T> it = values.iterator();
+        if (it.hasNext()) {
+            value = it.next();
+            if (it.hasNext()) {
+                throw new IllegalArgumentException(Errors.format(Errors.Keys.TooManyOccurrences_2, 1, getName()));
+            }
+        }
+        setValue(value);
     }
 
     /**
@@ -162,21 +181,21 @@ public class DefaultAttribute<T> extends
      *     If a report is provided, then it will contain at least the following information:
      *     <ul>
      *       <li>
-     *         The {@linkplain #getName() attribute name} as the data quality
+     *         <p>The {@linkplain #getName() attribute name} as the data quality
      *         {@linkplain org.apache.sis.metadata.iso.quality.DefaultDomainConsistency#getMeasureIdentification()
-     *         measure identification}.
+     *         measure identification}.</p>
      *
      *         <div class="note"><b>Note:</b> strictly speaking, {@code measureIdentification} identifies the
      *         <em>quality measurement</em>, not the “real” measurement itself. However this implementation
      *         uses the same set of identifiers for both for simplicity.</div>
      *       </li><li>
-     *         If the attribute {@linkplain #getValue() value} is not an {@linkplain Class#isInstance instance}
+     *         <p>If the attribute {@linkplain #getValue() value} is not an {@linkplain Class#isInstance instance}
      *         of the expected {@linkplain DefaultAttributeType#getValueClass() value class}, or if the number
      *         of occurrences is not inside the cardinality range, or if any other constraint is violated, then
      *         a {@linkplain org.apache.sis.metadata.iso.quality.DefaultConformanceResult conformance result} is
      *         added for each violation with an
      *         {@linkplain org.apache.sis.metadata.iso.quality.DefaultConformanceResult#getExplanation() explanation}
-     *         set to the error message.
+     *         set to the error message.</p>
      *
      *         <div class="warning"><b>Note:</b> this is a departure from ISO intend, since {@code explanation}
      *         should be a statement about what a successful conformance means. This point may be reformulated
@@ -214,56 +233,11 @@ public class DefaultAttribute<T> extends
      */
     public DataQuality quality() {
         final Validator v = new Validator(ScopeCode.ATTRIBUTE);
-        v.validate(type, value);
+        v.validate(type, getValue());
         return v.quality;
     }
 
     /**
-     * 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 DefaultAttribute<T> clone() throws CloneNotSupportedException {
-        return (DefaultAttribute<T>) super.clone();
-    }
-
-    /**
-     * Returns a hash code value for this attribute type.
-     *
-     * @return A hash code value.
-     */
-    @Override
-    public int hashCode() {
-        return type.hashCode() + Objects.hashCode(value);
-    }
-
-    /**
-     * Compares this attribute with the given object for equality.
-     *
-     * @return {@code true} if both objects are equal.
-     */
-    @Override
-    public boolean equals(final Object obj) {
-        if (obj == this) {
-            return true;
-        }
-        if (obj != null && obj.getClass() == getClass()) {
-            final DefaultAttribute<?> that = (DefaultAttribute<?>) obj;
-            return type.equals(that.type) &&
-                   Objects.equals(value, that.value);
-        }
-        return false;
-    }
-
-    /**
      * Returns a string representation of this attribute.
      * The returned string is for debugging purpose and may change in any future SIS version.
      *
@@ -272,10 +246,6 @@ public class DefaultAttribute<T> extends
     @Debug
     @Override
     public String toString() {
-        final StringBuilder buffer = type.toString("Attribute", Classes.getShortName(type.getValueClass()));
-        if (value != null) {
-            buffer.append(" = ").append(value);
-        }
-        return buffer.toString();
+        return type.toString("Attribute", Classes.getShortName(type.getValueClass()), getValues().iterator());
     }
 }

Modified: sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractFeature.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractFeature.java?rev=1596871&r1=1596870&r2=1596871&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractFeature.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractFeature.java [UTF-8] Thu May 22 13:50:53 2014
@@ -30,7 +30,7 @@ import org.apache.sis.util.CorruptedObje
  * Each feature instance can provide values for the following properties:
  *
  * <ul>
- *   <li>{@linkplain DefaultAttribute   Attributes}</li>
+ *   <li>{@linkplain AbstractAttribute  Attributes}</li>
  *   <li>{@linkplain DefaultAssociation Associations to other features}</li>
  *   <li>{@linkplain DefaultOperation   Operations}</li>
  * </ul>
@@ -62,7 +62,7 @@ import org.apache.sis.util.CorruptedObje
  *
  * @see DefaultFeatureType#newInstance()
  */
-public abstract class AbstractFeature implements Cloneable, Serializable {
+public abstract class AbstractFeature implements Serializable {
     /**
      * For cross-version compatibility.
      */
@@ -71,7 +71,7 @@ public abstract class AbstractFeature im
     /**
      * Information about the feature (name, characteristics, <i>etc.</i>).
      */
-    private final DefaultFeatureType type;
+    final DefaultFeatureType type;
 
     /**
      * Creates a new feature of the given type.
@@ -126,7 +126,7 @@ public abstract class AbstractFeature im
      *
      * <div class="note"><b>Tip:</b> This method returns the property <em>instance</em>. If only the property
      * <em>value</em> is desired, then {@link #getPropertyValue(String)} is preferred since it gives to SIS a
-     * chance to avoid the creation of {@link DefaultAttribute} or {@link DefaultAssociation} instances.</div>
+     * chance to avoid the creation of {@link AbstractAttribute} or {@link DefaultAssociation} instances.</div>
      *
      * @param  name The property name.
      * @return The property of the given name (never {@code null}).
@@ -178,7 +178,7 @@ public abstract class AbstractFeature im
     final Property createProperty(final String name, final Object value) {
         final PropertyType pt = getPropertyType(name);
         if (pt instanceof DefaultAttributeType<?>) {
-            return new DefaultAttribute<>((DefaultAttributeType<?>) pt, value);
+            return new SingletonAttribute<>((DefaultAttributeType<?>) pt, value);
         } else if (pt instanceof DefaultAssociationRole) {
             return new DefaultAssociation((DefaultAssociationRole) pt, (AbstractFeature) value);
         } else {
@@ -197,7 +197,7 @@ public abstract class AbstractFeature im
     final Property createProperty(final String name) throws IllegalArgumentException {
         final PropertyType pt = getPropertyType(name);
         if (pt instanceof DefaultAttributeType<?>) {
-            return new DefaultAttribute<>((DefaultAttributeType<?>) pt);
+            return new SingletonAttribute<>((DefaultAttributeType<?>) pt);
         } else if (pt instanceof DefaultAssociationRole) {
             return new DefaultAssociation((DefaultAssociationRole) pt);
         } else {
@@ -229,7 +229,7 @@ public abstract class AbstractFeature im
      *
      * <ul>
      *   <li>Get the property of the given name.</li>
-     *   <li>Delegates to {@link DefaultAttribute#getValue()} or {@link DefaultAssociation#getValue()},
+     *   <li>Delegates to {@link AbstractAttribute#getValue()} or {@link DefaultAssociation#getValue()},
      *       depending on the property type.
      * </ul>
      *
@@ -237,7 +237,7 @@ public abstract class AbstractFeature im
      * @return The value for the given property, or {@code null} if none.
      * @throws IllegalArgumentException If the given argument is not an attribute or association name of this feature.
      *
-     * @see DefaultAttribute#getValue()
+     * @see AbstractAttribute#getValue()
      */
     public abstract Object getPropertyValue(final String name) throws IllegalArgumentException;
 
@@ -255,7 +255,7 @@ public abstract class AbstractFeature im
      * @throws ClassCastException If the value is not assignable to the expected value class.
      * @throws IllegalArgumentException If the given value can not be assigned for an other reason.
      *
-     * @see DefaultAttribute#setValue(Object)
+     * @see AbstractAttribute#setValue(Object)
      */
     public abstract void setPropertyValue(final String name, final Object value) throws IllegalArgumentException;
 
@@ -263,8 +263,8 @@ public abstract class AbstractFeature im
      * Sets the value of the given property, with some minimal checks.
      */
     static void setPropertyValue(final Property property, final Object value) {
-        if (property instanceof DefaultAttribute<?>) {
-            setAttributeValue((DefaultAttribute<?>) property, value);
+        if (property instanceof AbstractAttribute<?>) {
+            setAttributeValue((AbstractAttribute<?>) property, value);
         } else if (property instanceof DefaultAssociation) {
             ArgumentChecks.ensureCanCast("value", AbstractFeature.class, value);
             setAssociationValue((DefaultAssociation) property, (AbstractFeature) value);
@@ -279,7 +279,7 @@ public abstract class AbstractFeature im
      * use {@link Validator} instead.
      */
     @SuppressWarnings("unchecked")
-    private static <T> void setAttributeValue(final DefaultAttribute<T> attribute, final Object value) {
+    private static <T> void setAttributeValue(final AbstractAttribute<T> attribute, final Object value) {
         if (value != null) {
             final DefaultAttributeType<T> pt = attribute.getType();
             final Class<?> base = pt.getValueClass();
@@ -288,7 +288,7 @@ public abstract class AbstractFeature im
                         pt.getName(), value.getClass()));
             }
         }
-        ((DefaultAttribute) attribute).setValue(value);
+        ((AbstractAttribute) attribute).setValue(value);
     }
 
     /**
@@ -368,8 +368,8 @@ public abstract class AbstractFeature im
      */
     final void verifyPropertyType(final String name, final Property property) {
         final PropertyType type;
-        if (property instanceof DefaultAttribute<?>) {
-            type = ((DefaultAttribute<?>) property).getType();
+        if (property instanceof AbstractAttribute<?>) {
+            type = ((AbstractAttribute<?>) property).getType();
         } else if (property instanceof DefaultAssociation) {
             type = ((DefaultAssociation) property).getRole();
         } else {
@@ -405,7 +405,7 @@ public abstract class AbstractFeature im
      *     element per property. Implementations are free to omit element for properties having nothing to report.
      *   </li><li>
      *     Each report may have one or more {@linkplain org.apache.sis.metadata.iso.quality.DefaultConformanceResult
-     *     conformance result}, as documented on {@link DefaultAttribute#quality()} javadoc.
+     *     conformance result}, as documented on {@link AbstractAttribute#quality()} javadoc.
      *   </li>
      * </ul>
      *
@@ -433,7 +433,7 @@ public abstract class AbstractFeature im
      *
      * @return Reports on all constraint violations found.
      *
-     * @see DefaultAttribute#quality()
+     * @see AbstractAttribute#quality()
      * @see DefaultAssociation#quality()
      */
     public DataQuality quality() {
@@ -441,8 +441,8 @@ public abstract class AbstractFeature im
         for (final String name : type.indices().keySet()) {
             final Property property = (Property) getProperty(name);
             final DataQuality quality;
-            if (property instanceof DefaultAttribute<?>) {
-                quality = ((DefaultAttribute<?>) property).quality();
+            if (property instanceof AbstractAttribute<?>) {
+                quality = ((AbstractAttribute<?>) property).quality();
             } else if (property instanceof DefaultAssociation) {
                 quality = ((DefaultAssociation) property).quality();
             } else {
@@ -456,45 +456,6 @@ public abstract class AbstractFeature im
     }
 
     /**
-     * Returns a copy of this feature
-     * This method clones also all {@linkplain Cloneable cloneable} property instances in this feature,
-     * but not necessarily property values. Whether the property values are cloned or not (i.e. whether
-     * the clone operation is <cite>deep</cite> or <cite>shallow</cite>) depends on the behavior or
-     * property {@code clone()} methods (see for example {@link DefaultAttribute#clone()}).
-     *
-     * @return A clone of this attribute.
-     * @throws CloneNotSupportedException if this feature can not be cloned, typically because
-     *         {@code clone()} on a property instance failed.
-     */
-    @Override
-    public AbstractFeature clone() throws CloneNotSupportedException {
-        return (AbstractFeature) super.clone();
-    }
-
-    /**
-     * Returns a hash code value for this feature.
-     *
-     * @return A hash code value.
-     */
-    @Override
-    public int hashCode() {
-        return type.hashCode();
-    }
-
-    /**
-     * Compares this feature with the given object for equality.
-     *
-     * @return {@code true} if both objects are equal.
-     */
-    @Override
-    public boolean equals(final Object obj) {
-        if (obj != null && obj.getClass() == getClass()) {
-            return type.equals(((AbstractFeature) obj).type);
-        }
-        return false;
-    }
-
-    /**
      * Formats this feature in a tabular format.
      *
      * @return A string representation of this feature in a tabular format.

Modified: sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultAssociation.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultAssociation.java?rev=1596871&r1=1596870&r2=1596871&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultAssociation.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultAssociation.java [UTF-8] Thu May 22 13:50:53 2014
@@ -159,7 +159,7 @@ public class DefaultAssociation extends 
      * This method returns at most one {@linkplain org.apache.sis.metadata.iso.quality.DefaultDataQuality#getReports()
      * report} with a {@linkplain org.apache.sis.metadata.iso.quality.DefaultDomainConsistency#getResults() result} for
      * each constraint violations found, if any.
-     * See {@link DefaultAttribute#quality()} for an example.
+     * See {@link AbstractAttribute#quality()} for an example.
      *
      * <p>This association is valid if this method does not report any
      * {@linkplain org.apache.sis.metadata.iso.quality.DefaultConformanceResult conformance result} having a

Modified: sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultAttributeType.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultAttributeType.java?rev=1596871&r1=1596870&r2=1596871&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultAttributeType.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultAttributeType.java [UTF-8] Thu May 22 13:50:53 2014
@@ -62,7 +62,7 @@ import java.util.Objects;
  * Such immutable instances can be shared by many objects and passed between threads without synchronization.
  *
  * <p>In particular, the {@link #getDefaultValue()} method does <strong>not</strong> clone the returned value.
- * This means that the same {@code defaultValue} instance may be shared by many {@link DefaultAttribute} instances.
+ * This means that the same {@code defaultValue} instance may be shared by many {@link AbstractAttribute} instances.
  * Consequently the default value should be immutable for avoiding unexpected behavior.</p>
  *
  * @param <T> The type of attribute values.
@@ -73,7 +73,7 @@ import java.util.Objects;
  * @version 0.5
  * @module
  *
- * @see DefaultAttribute
+ * @see AbstractAttribute
  */
 public class DefaultAttributeType<T> extends FieldType {
     /**
@@ -168,10 +168,13 @@ public class DefaultAttributeType<T> ext
      */
 
     /**
-     * Returns the minimum number of occurrences of the property within its containing entity.
+     * Returns the minimum number of attribute values.
      * The returned value is greater than or equal to zero.
      *
-     * @return The minimum number of occurrences of the property within its containing entity.
+     * <p>To be valid, an {@code Attribute} instance of this {@code AttributeType} shall have at least
+     * this minimum number of elements in its {@link AbstractAttribute#getValues() collection of values}.</p>
+     *
+     * @return The minimum number of attribute values.
      */
     @Override
     public final int getMinimumOccurs() {
@@ -179,12 +182,14 @@ public class DefaultAttributeType<T> ext
     }
 
     /**
-     * Returns the maximum number of occurrences of the property within its containing entity.
+     * Returns the maximum number of attribute values.
      * The returned value is greater than or equal to the {@link #getMinimumOccurs()} value.
      * If there is no maximum, then this method returns {@link Integer#MAX_VALUE}.
      *
-     * @return The maximum number of occurrences of the property within its containing entity,
-     *         or {@link Integer#MAX_VALUE} if none.
+     * <p>To be valid, an {@code Attribute} instance of this {@code AttributeType} shall have no more than
+     * this maximum number of elements in its {@link AbstractAttribute#getValues() collection of values}.</p>
+     *
+     * @return The maximum number of attribute values, or {@link Integer#MAX_VALUE} if none.
      */
     @Override
     public final int getMaximumOccurs() {

Modified: sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/DenseFeature.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/DenseFeature.java?rev=1596871&r1=1596870&r2=1596871&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/DenseFeature.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/DenseFeature.java [UTF-8] Thu May 22 13:50:53 2014
@@ -38,7 +38,7 @@ import org.apache.sis.util.resources.Err
  * @see SparseFeature
  * @see DefaultFeatureType
  */
-final class DenseFeature extends AbstractFeature {
+final class DenseFeature extends AbstractFeature implements Cloneable {
     /**
      * For cross-version compatibility.
      */
@@ -162,8 +162,8 @@ final class DenseFeature extends Abstrac
             if (element != null) {
                 if (!(properties instanceof Property[])) {
                     return element; // Most common case.
-                } else if (element instanceof DefaultAttribute<?>) {
-                    return ((DefaultAttribute<?>) element).getValue();
+                } else if (element instanceof AbstractAttribute<?>) {
+                    return ((AbstractAttribute<?>) element).getValue();
                 } else if (element instanceof DefaultAssociation) {
                     return ((DefaultAssociation) element).getValue();
                 } else {
@@ -233,13 +233,18 @@ final class DenseFeature extends Abstrac
     }
 
     /**
-     * Returns a shallow copy of this feature.
-     * The properties are cloned, but not the property values.
-     *
-     * @return A clone of this feature.
+     * Returns a copy of this feature
+     * This method clones also all {@linkplain Cloneable cloneable} property instances in this feature,
+     * but not necessarily property values. Whether the property values are cloned or not (i.e. whether
+     * the clone operation is <cite>deep</cite> or <cite>shallow</cite>) depends on the behavior or
+     * property {@code clone()} methods.
+     *
+     * @return A clone of this attribute.
+     * @throws CloneNotSupportedException if this feature can not be cloned, typically because
+     *         {@code clone()} on a property instance failed.
      */
     @Override
-    public AbstractFeature clone() throws CloneNotSupportedException {
+    public DenseFeature clone() throws CloneNotSupportedException {
         final DenseFeature clone = (DenseFeature) super.clone();
         clone.properties = clone.properties.clone();
         if (clone.properties instanceof Property[]) {
@@ -262,7 +267,7 @@ final class DenseFeature extends Abstrac
      */
     @Override
     public int hashCode() {
-        return super.hashCode() + 37 * Arrays.hashCode(properties);
+        return type.hashCode() + 37 * Arrays.hashCode(properties);
     }
 
     /**
@@ -275,8 +280,9 @@ final class DenseFeature extends Abstrac
         if (obj == this) {
             return true;
         }
-        if (super.equals(obj)) {
-            return Arrays.equals(properties, ((DenseFeature) obj).properties);
+        if (obj instanceof DenseFeature) {
+            final DenseFeature that = (DenseFeature) obj;
+            return type.equals(that.type) && Arrays.equals(properties, that.properties);
         }
         return false;
     }

Modified: sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/FeatureFormat.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/FeatureFormat.java?rev=1596871&r1=1596870&r2=1596871&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/FeatureFormat.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/FeatureFormat.java [UTF-8] Thu May 22 13:50:53 2014
@@ -38,7 +38,7 @@ import org.apache.sis.util.resources.Voc
  * This format assumes a monospaced font and an encoding supporting drawing box characters (e.g. UTF-8).
  *
  * <div class="note"><b>Example:</b> a feature named “City” and containing 3 properties (“name”, “population” and
- * “twin town”) may be formatted like below. The two first properties are {@linkplain DefaultAttribute attributes}
+ * “twin town”) may be formatted like below. The two first properties are {@linkplain AbstractAttribute attributes}
  * while the last property is an {@linkplain DefaultAssociation association} to an other feature.
  *
  * {@preformat text

Modified: sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/Features.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/Features.java?rev=1596871&r1=1596870&r2=1596871&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/Features.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/Features.java [UTF-8] Thu May 22 13:50:53 2014
@@ -78,7 +78,7 @@ public final class Features extends Stat
      * @category verification
      */
     @SuppressWarnings("unchecked")
-    public static <T> DefaultAttribute<T> cast(final DefaultAttribute<?> attribute, final Class<T> valueClass)
+    public static <T> AbstractAttribute<T> cast(final AbstractAttribute<?> attribute, final Class<T> valueClass)
             throws ClassCastException
     {
         if (attribute != null) {
@@ -90,6 +90,6 @@ public final class Features extends Stat
                         attribute.getName(), valueClass, actual));
             }
         }
-        return (DefaultAttribute<T>) attribute;
+        return (AbstractAttribute<T>) attribute;
     }
 }

Modified: sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/FieldType.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/FieldType.java?rev=1596871&r1=1596870&r2=1596871&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/FieldType.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/FieldType.java [UTF-8] Thu May 22 13:50:53 2014
@@ -17,12 +17,18 @@
 package org.apache.sis.feature;
 
 import java.util.Map;
+import java.util.Iterator;
 import org.opengis.util.GenericName;
 import org.apache.sis.util.resources.Errors;
 
 
 /**
  * Base class of property types having a value and a cardinality.
+ * This include {@code AttributeType} and {@code AssociationRole}, but not {@code Operation}.
+ *
+ * <div class="note"><b>Analogy:</b> if we compare {@code FeatureType} to a class in the Java language,
+ * attributes and associations would be fields while operations would be methods. This analogy explains
+ * the {@code FieldType} name of this class.</div>
  *
  * @author  Johann Sorel (Geomatys)
  * @author  Martin Desruisseaux (Geomatys)
@@ -107,14 +113,19 @@ abstract class FieldType extends Propert
     public boolean equals(final Object obj) {
         if (super.equals(obj)) {
             final FieldType that = (FieldType) obj;
-            return minimumOccurs  == that.minimumOccurs  &&
-                   maximumOccurs  == that.maximumOccurs;
+            return minimumOccurs == that.minimumOccurs &&
+                   maximumOccurs == that.maximumOccurs;
         }
         return false;
     }
 
     /**
-     * Implementation of {@link #toString()} to be shared by subclasses and {@link DefaultAttribute#toString()}.
+     * Helper method for implementation of {@code PropertyType.toString()} methods.
+     * Example:
+     *
+     * {@preformat text
+     *     FooType[“name” : ValueClass]
+     * }
      */
     final StringBuilder toString(final String typeName, final Object valueName) {
         final StringBuilder buffer = new StringBuilder(40).append(typeName).append('[');
@@ -128,4 +139,33 @@ abstract class FieldType extends Propert
         }
         return buffer.append(valueName).append(']');
     }
+
+    /**
+     * Helper method for implementation of {@code Property.toString()} methods.
+     * Example:
+     *
+     * {@preformat text
+     *     FooType[“name” : ValueClass] = {value1, value2, ...}
+     * }
+     */
+    final String toString(final String typeName, final Object valueName, final Iterator<?> values) {
+        final StringBuilder buffer = toString(typeName, valueName);
+        if (values.hasNext()) {
+            final Object value = values.next();
+            final boolean isMultiValued = values.hasNext();
+            buffer.append(" = ");
+            if (isMultiValued) {
+                buffer.append('{');
+            }
+            buffer.append(value);
+            if (isMultiValued) {
+                buffer.append(", ").append(values.next());
+                if (values.hasNext()) {
+                    buffer.append(", ...");
+                }
+                buffer.append('}');
+            }
+        }
+        return buffer.toString();
+    }
 }

Modified: sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/PropertySingleton.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/PropertySingleton.java?rev=1596871&r1=1596870&r2=1596871&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/PropertySingleton.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/PropertySingleton.java [UTF-8] Thu May 22 13:50:53 2014
@@ -27,7 +27,7 @@ import static org.apache.sis.util.Argume
 
 /**
  * A list containing 0 or 1 value. This implementation is used in the very common case where a
- * {@link DefaultAttribute} accepts at most one value. Its main purpose is to reduce the amount
+ * {@link AbstractAttribute} accepts at most one value. Its main purpose is to reduce the amount
  * of objects in memory compared to {@link java.util.ArrayList}.
  *
  * <p>There is no need to keep long-lived references to instances of this class.
@@ -42,12 +42,12 @@ final class PropertySingleton<V> extends
     /**
      * The property where to read and write the value.
      */
-    private final DefaultAttribute<V> property;
+    private final AbstractAttribute<V> property;
 
     /**
      * Creates a new list for the value of the given property.
      */
-    PropertySingleton(final DefaultAttribute<V> property) {
+    PropertySingleton(final AbstractAttribute<V> property) {
         this.property = property;
     }
 

Copied: sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/SingletonAttribute.java (from r1596663, sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultAttribute.java)
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/SingletonAttribute.java?p2=sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/SingletonAttribute.java&p1=sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultAttribute.java&r1=1596663&r2=1596871&rev=1596871&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultAttribute.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/SingletonAttribute.java [UTF-8] Thu May 22 13:50:53 2014
@@ -16,33 +16,23 @@
  */
 package org.apache.sis.feature;
 
-import java.io.Serializable;
-import org.opengis.util.GenericName;
-import org.opengis.metadata.quality.DataQuality;
-import org.opengis.metadata.maintenance.ScopeCode;
-import org.apache.sis.util.Debug;
-import org.apache.sis.util.Classes;
-import org.apache.sis.util.ArgumentChecks;
-
 // Related to JDK7
 import java.util.Objects;
 
 
 /**
- * An instance of an {@linkplain DefaultAttributeType attribute type} containing the value of an attribute in a feature.
- * {@code Attribute} holds two main information:
+ * An instance of an {@linkplain DefaultAttributeType attribute type} containing at most one value.
+ * The majority of features types contain attributes restricted to such [0 … 1] cardinality.
+ * While {@link MultiValuedAttribute} would be suitable to all cases, this {@code SingletonAttribute}
+ * consumes less memory.
  *
+ * {@section Limitations}
  * <ul>
- *   <li>A reference to an {@linkplain DefaultAttributeType attribute type}
- *       which define the base Java type and domain of valid values.</li>
- *   <li>A value.</li>
+ *   <li><b>Multi-threading:</b> {@code SingletonAttribute} instances are <strong>not</strong> thread-safe.
+ *       Synchronization, if needed, shall be done externally by the caller.</li>
  * </ul>
  *
- * {@section Usage in multi-thread environment}
- * {@code DefaultAttribute} are <strong>not</strong> thread-safe.
- * Synchronization, if needed, shall be done externally by the caller.
- *
- * @param <T> The type of attribute values.
+ * @param <T> The type of the attribute value.
  *
  * @author  Johann Sorel (Geomatys)
  * @author  Martin Desruisseaux (Geomatys)
@@ -52,19 +42,14 @@ import java.util.Objects;
  *
  * @see DefaultAttributeType
  */
-public class DefaultAttribute<T> extends Property implements Cloneable, Serializable {
+final class SingletonAttribute<T> extends AbstractAttribute<T> implements Cloneable {
     /**
      * For cross-version compatibility.
      */
-    private static final long serialVersionUID = -8103788797446754561L;
-
-    /**
-     * Information about the attribute (base Java class, domain of values, <i>etc.</i>).
-     */
-    private final DefaultAttributeType<T> type;
+    private static final long serialVersionUID = -2236273725166545505L;
 
     /**
-     * The attribute value.
+     * The attribute value, or {@code null} if none.
      */
     private T value;
 
@@ -74,10 +59,9 @@ public class DefaultAttribute<T> extends
      *
      * @param type Information about the attribute (base Java class, domain of values, <i>etc.</i>).
      */
-    public DefaultAttribute(final DefaultAttributeType<T> type) {
-        ArgumentChecks.ensureNonNull("type", type);
-        this.type  = type;
-        this.value = type.getDefaultValue();
+    public SingletonAttribute(final DefaultAttributeType<T> type) {
+        super(type);
+        value = type.getDefaultValue();
     }
 
     /**
@@ -87,42 +71,19 @@ public class DefaultAttribute<T> extends
      * @param type  Information about the attribute (base Java class, domain of values, <i>etc.</i>).
      * @param value The initial value (may be null {@code null}).
      */
-    public DefaultAttribute(final DefaultAttributeType<T> type, final Object value) {
-        ArgumentChecks.ensureNonNull("type", type);
-        this.type  = type;
+    SingletonAttribute(final DefaultAttributeType<T> type, final Object value) {
+        super(type);
         this.value = type.getValueClass().cast(value);
     }
 
     /**
-     * Returns the name of this attribute as defined by its {@linkplain #getType() type}.
-     * This convenience method delegates to {@link DefaultAttributeType#getName()}.
-     *
-     * @return The attribute name specified by its type.
-     */
-    @Override
-    public GenericName getName() {
-        return type.getName();
-    }
-
-    /**
-     * Returns information about the attribute (base Java class, domain of values, <i>etc.</i>).
-     *
-     * <div class="warning"><b>Warning:</b> In a future SIS version, the return type may be changed
-     * to {@code org.opengis.feature.AttributeType}. This change is pending GeoAPI revision.</div>
-     *
-     * @return Information about the attribute.
-     */
-    public DefaultAttributeType<T> getType() {
-        return type;
-    }
-
-    /**
      * Returns the attribute value.
      *
      * @return The attribute value (may be {@code null}).
      *
      * @see AbstractFeature#getPropertyValue(String)
      */
+    @Override
     public T getValue() {
         return value;
     }
@@ -130,95 +91,14 @@ public class DefaultAttribute<T> extends
     /**
      * Sets the attribute value.
      *
-     * {@section Validation}
-     * The amount of validation performed by this method is implementation dependent.
-     * Usually, only the most basic constraints are verified. This is so for performance reasons
-     * and also because some rules may be temporarily broken while constructing a feature.
-     * A more exhaustive verification can be performed by invoking the {@link #quality()} method.
-     *
      * @param value The new value.
-     *
-     * @see AbstractFeature#setPropertyValue(String, Object)
      */
+    @Override
     public void setValue(final T value) {
         this.value = value;
     }
 
     /**
-     * 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.
-     *
-     * <p>The default implementation reports data quality with at least the following information:</p>
-     * <ul>
-     *   <li>
-     *     The {@linkplain org.apache.sis.metadata.iso.quality.DefaultDataQuality#getScope() scope}
-     *     {@linkplain org.apache.sis.metadata.iso.quality.DefaultScope#getLevel() level} is set to
-     *     {@link org.opengis.metadata.maintenance.ScopeCode#ATTRIBUTE}.
-     *   </li><li>
-     *     At most one {@linkplain org.apache.sis.metadata.iso.quality.DefaultDomainConsistency domain consistency}
-     *     element is added to the {@linkplain org.apache.sis.metadata.iso.quality.DefaultDataQuality#getReports()
-     *     reports} list (implementations are free to omit that element if they have nothing to report).
-     *     If a report is provided, then it will contain at least the following information:
-     *     <ul>
-     *       <li>
-     *         The {@linkplain #getName() attribute name} as the data quality
-     *         {@linkplain org.apache.sis.metadata.iso.quality.DefaultDomainConsistency#getMeasureIdentification()
-     *         measure identification}.
-     *
-     *         <div class="note"><b>Note:</b> strictly speaking, {@code measureIdentification} identifies the
-     *         <em>quality measurement</em>, not the “real” measurement itself. However this implementation
-     *         uses the same set of identifiers for both for simplicity.</div>
-     *       </li><li>
-     *         If the attribute {@linkplain #getValue() value} is not an {@linkplain Class#isInstance instance}
-     *         of the expected {@linkplain DefaultAttributeType#getValueClass() value class}, or if the number
-     *         of occurrences is not inside the cardinality range, or if any other constraint is violated, then
-     *         a {@linkplain org.apache.sis.metadata.iso.quality.DefaultConformanceResult conformance result} is
-     *         added for each violation with an
-     *         {@linkplain org.apache.sis.metadata.iso.quality.DefaultConformanceResult#getExplanation() explanation}
-     *         set to the error message.
-     *
-     *         <div class="warning"><b>Note:</b> this is a departure from ISO intend, since {@code explanation}
-     *         should be a statement about what a successful conformance means. This point may be reformulated
-     *         in a future SIS version.</div>
-     *       </li>
-     *     </ul>
-     *   </li>
-     * </ul>
-     *
-     * This attribute is valid if this method does not report any
-     * {@linkplain org.apache.sis.metadata.iso.quality.DefaultConformanceResult conformance result} having a
-     * {@linkplain org.apache.sis.metadata.iso.quality.DefaultConformanceResult#pass() pass} value of {@code false}.
-     *
-     * <div class="note"><b>Example:</b> given an attribute named “population” with [1 … 1] cardinality,
-     * if no value has been assigned to that attribute, then this {@code quality()} method will return
-     * the following data quality report:
-     *
-     * {@preformat text
-     *   Data quality
-     *     ├─Scope
-     *     │   └─Level………………………………………………… Attribute
-     *     └─Report
-     *         ├─Measure identification
-     *         │   └─Code………………………………………… population
-     *         ├─Evaluation method type…… Direct internal
-     *         └─Result
-     *             ├─Explanation……………………… Missing value for “population” property.
-     *             └─Pass………………………………………… false
-     * }
-     * </div>
-     *
-     * @return Reports on all constraint violations found.
-     *
-     * @see AbstractFeature#quality()
-     */
-    public DataQuality quality() {
-        final Validator v = new Validator(ScopeCode.ATTRIBUTE);
-        v.validate(type, value);
-        return v.quality;
-    }
-
-    /**
      * 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.
@@ -231,8 +111,8 @@ public class DefaultAttribute<T> extends
      */
     @Override
     @SuppressWarnings("unchecked")
-    public DefaultAttribute<T> clone() throws CloneNotSupportedException {
-        return (DefaultAttribute<T>) super.clone();
+    public SingletonAttribute<T> clone() throws CloneNotSupportedException {
+        return (SingletonAttribute<T>) super.clone();
     }
 
     /**
@@ -255,27 +135,10 @@ public class DefaultAttribute<T> extends
         if (obj == this) {
             return true;
         }
-        if (obj != null && obj.getClass() == getClass()) {
-            final DefaultAttribute<?> that = (DefaultAttribute<?>) obj;
-            return type.equals(that.type) &&
-                   Objects.equals(value, that.value);
+        if (obj instanceof SingletonAttribute<?>) {
+            final SingletonAttribute<?> that = (SingletonAttribute<?>) obj;
+            return type.equals(that.type) && Objects.equals(value, that.value);
         }
         return false;
     }
-
-    /**
-     * Returns a string representation of this attribute.
-     * The returned string is for debugging purpose and may change in any future SIS version.
-     *
-     * @return A string representation of this attribute for debugging purpose.
-     */
-    @Debug
-    @Override
-    public String toString() {
-        final StringBuilder buffer = type.toString("Attribute", Classes.getShortName(type.getValueClass()));
-        if (value != null) {
-            buffer.append(" = ").append(value);
-        }
-        return buffer.toString();
-    }
 }

Modified: sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/SparseFeature.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/SparseFeature.java?rev=1596871&r1=1596870&r2=1596871&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/SparseFeature.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/SparseFeature.java [UTF-8] Thu May 22 13:50:53 2014
@@ -42,7 +42,7 @@ import org.apache.sis.util.CorruptedObje
  * @see DenseFeature
  * @see DefaultFeatureType
  */
-final class SparseFeature extends AbstractFeature {
+final class SparseFeature extends AbstractFeature implements Cloneable {
     /**
      * For cross-version compatibility.
      */
@@ -176,8 +176,8 @@ final class SparseFeature extends Abstra
         if (element != null) {
             if (valuesKind == VALUES) {
                 return element; // Most common case.
-            } else if (element instanceof DefaultAttribute<?>) {
-                return ((DefaultAttribute<?>) element).getValue();
+            } else if (element instanceof AbstractAttribute<?>) {
+                return ((AbstractAttribute<?>) element).getValue();
             } else if (element instanceof DefaultAssociation) {
                 return ((DefaultAssociation) element).getValue();
             } else if (valuesKind == PROPERTIES) {
@@ -246,7 +246,7 @@ final class SparseFeature extends Abstra
     public DataQuality quality() {
         if (valuesKind == VALUES) {
             final Validator v = new Validator(ScopeCode.FEATURE);
-            for (final String name : super.getType().indices().keySet()) {
+            for (final String name : type.indices().keySet()) {
                 v.validateAny(getPropertyType(name), properties.get(name));
             }
             return v.quality;
@@ -258,13 +258,18 @@ final class SparseFeature extends Abstra
     }
 
     /**
-     * Returns a copy of this feature.
-     * The properties are cloned, but not the property values.
-     *
-     * @return A clone of this feature.
+     * Returns a copy of this feature
+     * This method clones also all {@linkplain Cloneable cloneable} property instances in this feature,
+     * but not necessarily property values. Whether the property values are cloned or not (i.e. whether
+     * the clone operation is <cite>deep</cite> or <cite>shallow</cite>) depends on the behavior or
+     * property {@code clone()} methods.
+     *
+     * @return A clone of this attribute.
+     * @throws CloneNotSupportedException if this feature can not be cloned, typically because
+     *         {@code clone()} on a property instance failed.
      */
     @Override
-    public AbstractFeature clone() throws CloneNotSupportedException {
+    public SparseFeature clone() throws CloneNotSupportedException {
         final SparseFeature clone = (SparseFeature) super.clone();
         try {
             final Field field = SparseFeature.class.getDeclaredField("properties");
@@ -298,7 +303,7 @@ final class SparseFeature extends Abstra
      */
     @Override
     public int hashCode() {
-        return super.hashCode() + 37 * properties.hashCode();
+        return type.hashCode() + 37 * properties.hashCode();
     }
 
     /**
@@ -311,8 +316,9 @@ final class SparseFeature extends Abstra
         if (obj == this) {
             return true;
         }
-        if (super.equals(obj)) {
-            return properties.equals(((SparseFeature) obj).properties);
+        if (obj instanceof SparseFeature) {
+            final SparseFeature that = (SparseFeature) obj;
+            return type.equals(that.type) && properties.equals(that.properties);
         }
         return false;
     }

Modified: sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/package-info.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/package-info.java?rev=1596871&r1=1596870&r2=1596871&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/package-info.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/package-info.java [UTF-8] Thu May 22 13:50:53 2014
@@ -74,7 +74,7 @@
  * </td><td class="sep" style="width: 50%; white-space: nowrap">
  *             {@linkplain org.apache.sis.feature.AbstractFeature    Feature}<br>
  *                                                                   Property<br>
- * {@code  ├─} {@linkplain org.apache.sis.feature.DefaultAttribute   Attribute}<br>
+ * {@code  ├─} {@linkplain org.apache.sis.feature.AbstractAttribute  Attribute}<br>
  * {@code  └─} {@linkplain org.apache.sis.feature.DefaultAssociation Feature association}<br>
  * </td></tr></table>
  *

Modified: sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/CustomAttribute.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/CustomAttribute.java?rev=1596871&r1=1596870&r2=1596871&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/CustomAttribute.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/CustomAttribute.java [UTF-8] Thu May 22 13:50:53 2014
@@ -27,7 +27,7 @@ import static org.junit.Assert.*;
 
 
 /**
- * For testing {@link DefaultAttribute} customization.
+ * For testing {@link AbstractAttribute} customization.
  * This implementation adds its own criterion to the attribute quality evaluation.
  *
  * @author  Martin Desruisseaux (Geomatys)
@@ -36,17 +36,39 @@ import static org.junit.Assert.*;
  * @module
  */
 @SuppressWarnings("serial")
-final strictfp class CustomAttribute<V> extends DefaultAttribute<V> {
+final strictfp class CustomAttribute<V> extends AbstractAttribute<V> {
     /**
      * A quality information that this attribute will report in addition to the default ones.
      */
     static final String ADDITIONAL_QUALITY_INFO = "Some statistical quality measurement.";
 
     /**
+     * The singleton value.
+     */
+    private V value;
+
+    /**
      * Creates a new attribute.
      */
     public CustomAttribute(final DefaultAttributeType<V> type) {
         super(type);
+        value = type.getDefaultValue();
+    }
+
+    /**
+     * Returns the singleton value.
+     */
+    @Override
+    public V getValue() {
+        return value;
+    }
+
+    /**
+     * Sets the singleton value.
+     */
+    @Override
+    public void setValue(final V value) {
+        this.value = value;
     }
 
     /**

Modified: sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/DefaultOperationTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/DefaultOperationTest.java?rev=1596871&r1=1596870&r2=1596871&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/DefaultOperationTest.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/DefaultOperationTest.java [UTF-8] Thu May 22 13:50:53 2014
@@ -35,7 +35,7 @@ import static org.apache.sis.test.Assert
  * @version 0.5
  * @module
  */
-@DependsOn(DefaultAttributeTest.class)
+@DependsOn(SingletonAttributeTest.class)
 public final strictfp class DefaultOperationTest extends TestCase {
     /**
      * Returns an operation that found new cities.

Modified: sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/DenseFeatureTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/DenseFeatureTest.java?rev=1596871&r1=1596870&r2=1596871&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/DenseFeatureTest.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/DenseFeatureTest.java [UTF-8] Thu May 22 13:50:53 2014
@@ -21,6 +21,7 @@ import org.apache.sis.test.DependsOn;
 
 /**
  * Tests {@link DenseFeature}.
+ * This class inherits all tests defined in {@link FeatureTestCase}.
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.5
@@ -29,7 +30,7 @@ import org.apache.sis.test.DependsOn;
  */
 @DependsOn({
     DefaultFeatureTypeTest.class,
-    DefaultAttributeTest.class,
+    SingletonAttributeTest.class,
     PropertySingletonTest.class
 })
 public final strictfp class DenseFeatureTest extends FeatureTestCase {
@@ -41,5 +42,13 @@ public final strictfp class DenseFeature
         return new DenseFeature(type);
     }
 
+    /**
+     * Clones the {@link #feature} instance.
+     */
+    @Override
+    final AbstractFeature cloneFeature() throws CloneNotSupportedException {
+        return ((DenseFeature) feature).clone();
+    }
+
     // Inherit all tests from the super-class.
 }

Modified: sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/FeatureTestCase.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/FeatureTestCase.java?rev=1596871&r1=1596870&r2=1596871&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/FeatureTestCase.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/FeatureTestCase.java [UTF-8] Thu May 22 13:50:53 2014
@@ -43,7 +43,7 @@ public abstract strictfp class FeatureTe
     /**
      * The feature being tested.
      */
-    private AbstractFeature feature;
+    AbstractFeature feature;
 
     /**
      * {@code true} if {@link #getAttributeValue(String)} should invoke {@link AbstractFeature#getProperty(String)},
@@ -84,19 +84,24 @@ public abstract strictfp class FeatureTe
     abstract AbstractFeature createFeature(final DefaultFeatureType type);
 
     /**
+     * Clones the {@link #feature} instance.
+     */
+    abstract AbstractFeature cloneFeature() throws CloneNotSupportedException;
+
+    /**
      * Returns the attribute value of the current {@link #feature} for the given name.
      */
     private Object getAttributeValue(final String name) {
         final Object value = feature.getPropertyValue(name);
         if (getValuesFromProperty) {
             final Property property = (Property) feature.getProperty(name);
-            assertInstanceOf(name, DefaultAttribute.class, property);
+            assertInstanceOf(name, AbstractAttribute.class, property);
 
             // The AttributeType shall be the same than the one provided by FeatureType for the given name.
-            assertSame(name, feature.getType().getProperty(name), ((DefaultAttribute<?>) property).getType());
+            assertSame(name, feature.getType().getProperty(name), ((AbstractAttribute<?>) property).getType());
 
             // Attribute value shall be the same than the one provided by FeatureType convenience method.
-            assertSame(name, feature.getPropertyValue(name), ((DefaultAttribute<?>) property).getValue());
+            assertSame(name, feature.getPropertyValue(name), ((AbstractAttribute<?>) property).getValue());
 
             // Invoking getProperty(name) twice shall return the same Property instance.
             assertSame(name, property, feature.getProperty(name));
@@ -223,7 +228,7 @@ public abstract strictfp class FeatureTe
     @DependsOnMethod({"testSimpleValues", "testSimpleProperties"})
     public void testCustomAttribute() {
         feature = createFeature(DefaultFeatureTypeTest.city());
-        final DefaultAttribute<String> wrong = DefaultAttributeTest.parliament();
+        final AbstractAttribute<String> wrong = SingletonAttributeTest.parliament();
         final CustomAttribute<String> city = new CustomAttribute<>(Features.cast(
                 (DefaultAttributeType<?>) feature.getType().getProperty("city"), String.class));
 
@@ -294,7 +299,7 @@ public abstract strictfp class FeatureTe
     private void testClone(final String property, final Object oldValue, final Object newValue)
             throws CloneNotSupportedException
     {
-        final AbstractFeature clone = feature.clone();
+        final AbstractFeature clone = cloneFeature();
         assertNotSame("clone",      clone, feature);
         assertTrue   ("equals",     clone.equals(feature));
         assertTrue   ("hashCode",   clone.hashCode() == feature.hashCode());

Modified: sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/FeaturesTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/FeaturesTest.java?rev=1596871&r1=1596870&r2=1596871&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/FeaturesTest.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/FeaturesTest.java [UTF-8] Thu May 22 13:50:53 2014
@@ -31,7 +31,7 @@ import static org.junit.Assert.*;
  * @version 0.5
  * @module
  */
-@DependsOn(DefaultAttributeTest.class)
+@DependsOn(SingletonAttributeTest.class)
 public final strictfp class FeaturesTest extends TestCase {
     /**
      * Tests {@link Features#cast(AttributeType, Class)}.
@@ -56,7 +56,7 @@ public final strictfp class FeaturesTest
      */
     @Test
     public void testCastAttributeInstance() {
-        final DefaultAttribute<String> parliament = DefaultAttributeTest.parliament();
+        final AbstractAttribute<String> parliament = SingletonAttributeTest.parliament();
         assertSame(parliament, Features.cast(parliament, String.class));
         try {
             Features.cast(parliament, CharSequence.class);

Modified: sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/PropertySingletonTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/PropertySingletonTest.java?rev=1596871&r1=1596870&r2=1596871&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/PropertySingletonTest.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/PropertySingletonTest.java [UTF-8] Thu May 22 13:50:53 2014
@@ -36,7 +36,7 @@ import static org.apache.sis.test.TestUt
  * @version 0.5
  * @module
  */
-@DependsOn(DefaultAttributeTest.class)
+@DependsOn(SingletonAttributeTest.class)
 public final strictfp class PropertySingletonTest extends TestCase {
     /**
      * The instance to test.
@@ -46,13 +46,13 @@ public final strictfp class PropertySing
     /**
      * The attribute wrapped by the {@link #singleton} list.
      */
-    private final DefaultAttribute<Integer> attribute;
+    private final AbstractAttribute<Integer> attribute;
 
     /**
      * Creates a new test case.
      */
     public PropertySingletonTest() {
-        attribute = new DefaultAttribute<>(new DefaultAttributeType<>(
+        attribute = new SingletonAttribute<>(new DefaultAttributeType<>(
                 singletonMap(DefaultAttributeType.NAME_KEY, "test"), Integer.class, 0, 1, null));
         singleton = new PropertySingleton<>(attribute);
     }

Copied: sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/SingletonAttributeTest.java (from r1596663, sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/DefaultAttributeTest.java)
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/SingletonAttributeTest.java?p2=sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/SingletonAttributeTest.java&p1=sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/DefaultAttributeTest.java&r1=1596663&r2=1596871&rev=1596871&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/DefaultAttributeTest.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/SingletonAttributeTest.java [UTF-8] Thu May 22 13:50:53 2014
@@ -32,7 +32,7 @@ import static org.apache.sis.test.TestUt
 
 
 /**
- * Tests {@link DefaultAttribute}.
+ * Tests {@link SingletonAttribute}.
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.5
@@ -40,29 +40,29 @@ import static org.apache.sis.test.TestUt
  * @module
  */
 @DependsOn(DefaultAttributeTypeTest.class)
-public final strictfp class DefaultAttributeTest extends TestCase {
+public final strictfp class SingletonAttributeTest extends TestCase {
     /**
      * Creates an attribute for the city name.
      * This attribute has a default value.
      */
-    static DefaultAttribute<String> city() {
-        return new DefaultAttribute<>(DefaultAttributeTypeTest.city(new HashMap<>(4)));
+    static SingletonAttribute<String> city() {
+        return new SingletonAttribute<>(DefaultAttributeTypeTest.city(new HashMap<>(4)));
     }
 
     /**
      * Creates an attribute for a singleton value.
      * This attribute has no default value.
      */
-    static DefaultAttribute<Integer> population() {
-        return new DefaultAttribute<>(DefaultAttributeTypeTest.population(new HashMap<>(4)));
+    static SingletonAttribute<Integer> population() {
+        return new SingletonAttribute<>(DefaultAttributeTypeTest.population(new HashMap<>(4)));
     }
 
     /**
      * Creates an attribute for a singleton value.
      * This attribute has no default value.
      */
-    static DefaultAttribute<String> parliament() {
-        return new DefaultAttribute<>(DefaultAttributeTypeTest.parliament());
+    static SingletonAttribute<String> parliament() {
+        return new SingletonAttribute<>(DefaultAttributeTypeTest.parliament());
     }
 
     /**
@@ -70,7 +70,7 @@ public final strictfp class DefaultAttri
      */
     @Test
     public void testValue() {
-        final DefaultAttribute<Integer> attribute = population();
+        final AbstractAttribute<Integer> attribute = population();
         assertNull("value", attribute.getValue());
         attribute.setValue(1000);
         assertEquals("value", Integer.valueOf(1000), attribute.getValue());
@@ -79,13 +79,13 @@ public final strictfp class DefaultAttri
     }
 
     /**
-     * Tests {@link DefaultAttribute#quality()}.
+     * Tests {@link SingletonAttribute#quality()}.
      */
     @Test
     @DependsOnMethod("testValue")
     @SuppressWarnings("unchecked")
     public void testQuality() {
-        final DefaultAttribute<Integer> attribute = population();
+        final AbstractAttribute<Integer> attribute = population();
         DataQuality quality = attribute.quality();
         assertEquals("scope.level", ScopeCode.ATTRIBUTE, quality.getScope().getLevel());
         assertDomainConsistencyEquals("population", "Missing value for “population” property.",
@@ -93,7 +93,7 @@ public final strictfp class DefaultAttri
         /*
          * Intentionally store a value of the wrong type, and test again.
          */
-        ((DefaultAttribute) attribute).setValue(4.5f);
+        ((AbstractAttribute) attribute).setValue(4.5f);
         quality = attribute.quality();
         assertEquals("scope.level", ScopeCode.ATTRIBUTE, quality.getScope().getLevel());
         assertDomainConsistencyEquals("population", "Property “population” does not accept instances of ‘Float’.",
@@ -121,8 +121,8 @@ public final strictfp class DefaultAttri
      */
     @Test
     public void testEquals() {
-        final DefaultAttribute<Integer> a1 = population();
-        final DefaultAttribute<Integer> a2 = population();
+        final AbstractAttribute<Integer> a1 = population();
+        final AbstractAttribute<Integer> a2 = population();
         assertFalse("equals(null)", a1.equals(null));
         testEquals(a1, a2);
     }
@@ -130,7 +130,7 @@ public final strictfp class DefaultAttri
     /**
      * Implementation of {@link #testEquals()} used also by {@link #testClone()}.
      */
-    private static void testEquals(final DefaultAttribute<Integer> a1, final DefaultAttribute<Integer> a2) {
+    private static void testEquals(final AbstractAttribute<Integer> a1, final AbstractAttribute<Integer> a2) {
         assertTrue  ("equals",   a1.equals(a2));
         assertEquals("hashCode", a1.hashCode(), a2.hashCode());
         a2.setValue(1000);
@@ -139,15 +139,15 @@ public final strictfp class DefaultAttri
     }
 
     /**
-     * Tests {@link DefaultAttribute#clone()}.
+     * Tests {@link SingletonAttribute#clone()}.
      *
      * @throws CloneNotSupportedException Should never happen.
      */
     @Test
     @DependsOnMethod("testEquals")
     public void testClone() throws CloneNotSupportedException {
-        final DefaultAttribute<Integer> a1 = population();
-        final DefaultAttribute<Integer> a2 = a1.clone();
+        final SingletonAttribute<Integer> a1 = population();
+        final SingletonAttribute<Integer> a2 = a1.clone();
         assertNotSame(a1, a2);
         testEquals(a1, a2);
     }
@@ -158,17 +158,17 @@ public final strictfp class DefaultAttri
     @Test
     @DependsOnMethod("testEquals")
     public void testSerialization() {
-        final DefaultAttribute<String> attribute = city();
+        final AbstractAttribute<String> attribute = city();
         assertNotSame(attribute, assertSerializedEquals(attribute));
     }
 
     /**
-     * Tests {@link DefaultAttribute#toString()}.
+     * Tests {@link SingletonAttribute#toString()}.
      */
     @Test
     @DependsOnMethod("testValue")
     public void testToString() {
-        final DefaultAttribute<String> city = city();
+        final AbstractAttribute<String> city = city();
         assertEquals("Attribute[“city” : String] = Utopia", city.toString());
         city.setValue("Dystopia");
         assertEquals("Attribute[“city” : String] = Dystopia", city.toString());

Modified: sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/SparseFeatureTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/SparseFeatureTest.java?rev=1596871&r1=1596870&r2=1596871&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/SparseFeatureTest.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/SparseFeatureTest.java [UTF-8] Thu May 22 13:50:53 2014
@@ -21,6 +21,7 @@ import org.apache.sis.test.DependsOn;
 
 /**
  * Tests {@link SparseFeature}.
+ * This class inherits all tests defined in {@link FeatureTestCase}.
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.5
@@ -29,7 +30,7 @@ import org.apache.sis.test.DependsOn;
  */
 @DependsOn({
     DefaultFeatureTypeTest.class,
-    DefaultAttributeTest.class,
+    SingletonAttributeTest.class,
     PropertySingletonTest.class
 })
 public final strictfp class SparseFeatureTest extends FeatureTestCase {
@@ -41,5 +42,13 @@ public final strictfp class SparseFeatur
         return new SparseFeature(type);
     }
 
+    /**
+     * Clones the {@link #feature} instance.
+     */
+    @Override
+    final AbstractFeature cloneFeature() throws CloneNotSupportedException {
+        return ((SparseFeature) feature).clone();
+    }
+
     // Inherit all tests from the super-class.
 }

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=1596871&r1=1596870&r2=1596871&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] Thu May 22 13:50:53 2014
@@ -32,7 +32,7 @@ import org.junit.BeforeClass;
 @Suite.SuiteClasses({
     org.apache.sis.feature.DefaultAttributeTypeTest.class,
     org.apache.sis.feature.DefaultFeatureTypeTest.class,
-    org.apache.sis.feature.DefaultAttributeTest.class,
+    org.apache.sis.feature.SingletonAttributeTest.class,
     org.apache.sis.feature.PropertySingletonTest.class,
     org.apache.sis.feature.DenseFeatureTest.class,
     org.apache.sis.feature.SparseFeatureTest.class,

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/parameter/ParameterValueList.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/parameter/ParameterValueList.java?rev=1596871&r1=1596870&r2=1596871&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/parameter/ParameterValueList.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/parameter/ParameterValueList.java [UTF-8] Thu May 22 13:50:53 2014
@@ -205,9 +205,10 @@ final class ParameterValueList extends A
                 count++;
             }
         }
-        if (count >= desc.getMaximumOccurs()) {
+        final int max = desc.getMaximumOccurs();
+        if (count >= max) {
             throw new InvalidParameterCardinalityException(Errors.format(
-                    Errors.Keys.TooManyOccurrences_2, count, name), name.getCode());
+                    Errors.Keys.TooManyOccurrences_2, max, name), name.getCode());
         }
         addUnchecked(parameter);
         modCount++;
@@ -260,9 +261,10 @@ final class ParameterValueList extends A
                 count++;
             }
         }
-        if (count >= desc.getMaximumOccurs()) {
+        final int max = desc.getMaximumOccurs();
+        if (count >= max) {
             throw new InvalidParameterCardinalityException(Errors.format(
-                    Errors.Keys.TooManyOccurrences_2, count, name), name.getCode());
+                    Errors.Keys.TooManyOccurrences_2, max, name), name.getCode());
         }
     }
 

Modified: sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/util/Cloner.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/util/Cloner.java?rev=1596871&r1=1596870&r2=1596871&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/util/Cloner.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/util/Cloner.java [UTF-8] Thu May 22 13:50:53 2014
@@ -17,6 +17,7 @@
 package org.apache.sis.internal.util;
 
 import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
 import java.lang.reflect.InvocationTargetException;
 import org.apache.sis.util.Workaround;
 import org.apache.sis.util.resources.Errors;
@@ -28,7 +29,7 @@ import org.apache.sis.util.resources.Err
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.3 (derived from geotk-3.00)
- * @version 0.3
+ * @version 0.5
  * @module
  */
 @Workaround(library="JDK", version="1.7")
@@ -85,15 +86,42 @@ public class Cloner {
         if (object == null) {
             return null;
         }
+        SecurityException security = null;
         final Class<?> valueType = object.getClass();
         try {
             if (valueType != type) {
                 method = valueType.getMethod("clone", (Class<?>[]) null);
                 type = valueType; // Set only if the above line succeed.
-            }
-            if (method != null) { // May be null if previous call threw NoSuchMethodException.
+                /*
+                 * If the class implementing the 'clone()' method is not public, we may not be able to access that
+                 * method even if it is public. Try to make the method accessible. If we fail for security reason,
+                 * we will still attempt to clone (maybe a parent class is public), but we remember the exception
+                 * in order to report it in case of failure.
+                 */
+                if (!Modifier.isPublic(method.getDeclaringClass().getModifiers())) try {
+                    method.setAccessible(true);
+                } catch (SecurityException e) {
+                    security = e;
+                }
+            }
+            /*
+             * 'method' may be null if a previous call to this clone(Object) method threw NoSuchMethodException
+             * (see the first 'catch' block below). In this context, 'null' means "no public clone() method".
+             */
+            if (method != null) {
                 return method.invoke(object, (Object[]) null);
             }
+        } catch (NoSuchMethodException e) {
+            if (isCloneRequired(object)) {
+                throw fail(e);
+            }
+            method = null;
+            type = valueType;
+        } catch (IllegalAccessException e) {
+            if (security != null) {
+                e.addSuppressed(security);
+            }
+            throw fail(e);
         } catch (InvocationTargetException e) {
             final Throwable cause = e.getCause();
             if (cause instanceof CloneNotSupportedException) {
@@ -106,13 +134,7 @@ public class Cloner {
                 throw (Error) cause;
             }
             throw fail(e);
-        } catch (NoSuchMethodException e) {
-            if (isCloneRequired(object)) {
-                throw fail(e);
-            }
-            method = null;
-            type = valueType;
-        } catch (ReflectiveOperationException e) {
+        } catch (SecurityException e) {
             throw fail(e);
         }
         return object;

Modified: sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java?rev=1596871&r1=1596870&r2=1596871&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java [UTF-8] Thu May 22 13:50:53 2014
@@ -693,7 +693,7 @@ public final class Errors extends Indexe
         public static final short TooManyArguments_2 = 105;
 
         /**
-         * Too many occurrences of “{1}”. There is already {0} of them.
+         * Too many occurrences of “{1}”. The maximum is {0}.
          */
         public static final short TooManyOccurrences_2 = 149;
 

Modified: sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties?rev=1596871&r1=1596870&r2=1596871&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties [ISO-8859-1] (original)
+++ sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties [ISO-8859-1] Thu May 22 13:50:53 2014
@@ -150,7 +150,7 @@ StreamIsForwardOnly_1             = Can 
 TooFewArguments_2                 = Expected at least {0} argument{0,choice,1#|2#s}, but got {1}.
 TooFewOccurrences_2               = Too few occurrences of \u201c{1}\u201d. Expected at least {0} of them.
 TooManyArguments_2                = Expected at most {0} argument{0,choice,1#|2#s}, but got {1}.
-TooManyOccurrences_2              = Too many occurrences of \u201c{1}\u201d. There is already {0} of them.
+TooManyOccurrences_2              = Too many occurrences of \u201c{1}\u201d. The maximum is {0}.
 TreeDepthExceedsMaximum           = Tree depth exceeds the maximum.
 UndefinedOrderingForElements_2    = Ordering between \u201c{0}\u201d and \u201c{1}\u201d elements is undefined.
 UnexpectedArrayLength_2           = Expected an array of length {0}, but got {1}.

Modified: sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties?rev=1596871&r1=1596870&r2=1596871&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties [ISO-8859-1] (original)
+++ sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties [ISO-8859-1] Thu May 22 13:50:53 2014
@@ -139,7 +139,7 @@ StreamIsForwardOnly_1             = Ne p
 TooFewArguments_2                 = Au moins {0} argument{0,choice,1# \u00e9tait attendu|2#s \u00e9taient attendus}, mais seulement {1} {1,choice,1#a \u00e9t\u00e9 sp\u00e9cifi\u00e9|2#ont \u00e9t\u00e9 sp\u00e9cifi\u00e9s}.
 TooFewOccurrences_2               = Trop peu d\u2019occurrences de \u00ab\u202f{1}\u202f\u00bb. Il en faut au moins {0}.
 TooManyArguments_2                = Au plus {0} argument{0,choice,1# \u00e9tait attendu|2#s \u00e9taient attendus}, mais {1} {1,choice,1#a \u00e9t\u00e9 sp\u00e9cifi\u00e9|2#ont \u00e9t\u00e9 sp\u00e9cifi\u00e9s}.
-TooManyOccurrences_2              = Trop d\u2019occurrences de \u00ab\u202f{1}\u202f\u00bb. Il en existe d\u00e9j\u00e0 {0}.
+TooManyOccurrences_2              = Trop d\u2019occurrences de \u00ab\u202f{1}\u202f\u00bb. Le maximum est {0}.
 TreeDepthExceedsMaximum           = La profondeur de l\u2019arbre exc\u00e8de le maximum.
 UndefinedOrderingForElements_2    = L\u2019ordre entre les \u00e9l\u00e9ments \u00ab\u202f{0}\u202f\u00bb et \u00ab\u202f{1}\u202f\u00bb n\u2019est pas d\u00e9fini.
 UnexpectedArrayLength_2           = Un tableau de longueur {0} \u00e9tait attendu, mais le tableau re\u00e7u est de longueur {1}.



Mime
View raw message