sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1597095 - in /sis/branches/JDK8/core/sis-feature/src: main/java/org/apache/sis/feature/ test/java/org/apache/sis/feature/
Date Fri, 23 May 2014 13:45:41 GMT
Author: desruisseaux
Date: Fri May 23 13:45:40 2014
New Revision: 1597095

URL: http://svn.apache.org/r1597095
Log:
Apply to association the same pattern than for attribute (2/2): added MultiValuedAssociation.

Added:
    sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/MultiValuedAssociation.java
      - copied, changed from r1596975, sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/MultiValuedAttribute.java
Modified:
    sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractAssociation.java
    sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractAttribute.java
    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/DenseFeature.java
    sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/Field.java
    sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/MultiValuedAttribute.java
    sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/SingletonAssociation.java
    sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/SingletonAttribute.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/DefaultAssociationRoleTest.java
    sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/FeatureFormatTest.java
    sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/SingletonAssociationTest.java

Modified: sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractAssociation.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractAssociation.java?rev=1597095&r1=1597094&r2=1597095&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractAssociation.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractAssociation.java
[UTF-8] Fri May 23 13:45:40 2014
@@ -57,16 +57,44 @@ public abstract class AbstractAssociatio
     final DefaultAssociationRole role;
 
     /**
-     * Creates a new association of the given type.
+     * Creates a new association of the given role.
      *
      * @param role Information about the association.
+     *
+     * @see #create(DefaultAssociationRole)
      */
-    public AbstractAssociation(final DefaultAssociationRole role) {
-        ArgumentChecks.ensureNonNull("role", role);
+    protected AbstractAssociation(final DefaultAssociationRole role) {
         this.role = role;
     }
 
     /**
+     * Creates a new association of the given role.
+     *
+     * @param  role Information about the association.
+     * @return The new association.
+     */
+    public static AbstractAssociation create(final DefaultAssociationRole role) {
+        ArgumentChecks.ensureNonNull("role", role);
+        return isSingleton(role.getMaximumOccurs())
+               ? new SingletonAssociation(role)
+               : new MultiValuedAssociation(role);
+    }
+
+    /**
+     * Creates a new association of the given role initialized to the given value.
+     *
+     * @param  role  Information about the association.
+     * @param  value The initial value (may be {@code null}).
+     * @return The new association.
+     */
+    static AbstractAssociation create(final DefaultAssociationRole role, final Object value)
{
+        ArgumentChecks.ensureNonNull("role", role);
+        return isSingleton(role.getMaximumOccurs())
+               ? new SingletonAssociation(role, (AbstractFeature) value)
+               : new MultiValuedAssociation(role, value);
+    }
+
+    /**
      * Returns the name of this association as defined by its {@linkplain #getRole() role}.
      * This convenience method delegates to {@link DefaultAssociationRole#getName()}.
      *
@@ -141,7 +169,7 @@ public abstract class AbstractAssociatio
     public abstract void setValue(final AbstractFeature value);
 
     /**
-     * Set the features. All previous values are replaced by the given collection.
+     * Sets the features. 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(AbstractFeature)}.</p>

Modified: sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractAttribute.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractAttribute.java?rev=1597095&r1=1597094&r2=1597095&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractAttribute.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractAttribute.java
[UTF-8] Fri May 23 13:45:40 2014
@@ -70,6 +70,8 @@ public abstract class AbstractAttribute<
      * Creates a new attribute of the given type.
      *
      * @param type Information about the attribute (base Java class, domain of values, <i>etc.</i>).
+     *
+     * @see #create(DefaultAttributeType)
      */
     protected AbstractAttribute(final DefaultAttributeType<V> type) {
         this.type = type;
@@ -85,7 +87,7 @@ public abstract class AbstractAttribute<
      */
     public static <V> AbstractAttribute<V> create(final DefaultAttributeType<V>
type) {
         ArgumentChecks.ensureNonNull("type", type);
-        return (type.getMaximumOccurs() <= 1)
+        return isSingleton(type.getMaximumOccurs())
                ? new SingletonAttribute<>(type)
                : new MultiValuedAttribute<>(type);
     }
@@ -101,7 +103,7 @@ public abstract class AbstractAttribute<
      */
     static <V> AbstractAttribute<V> create(final DefaultAttributeType<V>
type, final Object value) {
         ArgumentChecks.ensureNonNull("type", type);
-        return (type.getMaximumOccurs() <= 1)
+        return isSingleton(type.getMaximumOccurs())
                ? new SingletonAttribute<>(type, value)
                : new MultiValuedAttribute<>(type, value);
     }
@@ -174,7 +176,7 @@ public abstract class AbstractAttribute<
     public abstract void setValue(final V value);
 
     /**
-     * Set the attribute values. All previous values are replaced by the given collection.
+     * Sets 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>

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=1597095&r1=1597094&r2=1597095&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] Fri May 23 13:45:40 2014
@@ -81,8 +81,10 @@ public abstract class AbstractFeature im
      * Creates a new feature of the given type.
      *
      * @param type Information about the feature (name, characteristics, <i>etc.</i>).
+     *
+     * @see DefaultFeatureType#newInstance()
      */
-    public AbstractFeature(final DefaultFeatureType type) {
+    protected AbstractFeature(final DefaultFeatureType type) {
         ArgumentChecks.ensureNonNull("type", type);
         this.type = type;
     }
@@ -184,7 +186,7 @@ public abstract class AbstractFeature im
         if (pt instanceof DefaultAttributeType<?>) {
             return AbstractAttribute.create((DefaultAttributeType<?>) pt, value);
         } else if (pt instanceof DefaultAssociationRole) {
-            return new SingletonAssociation((DefaultAssociationRole) pt, (AbstractFeature)
value);
+            return AbstractAssociation.create((DefaultAssociationRole) pt, value);
         } else {
             // Should never happen, unless the user gave us some mutable FeatureType.
             throw new CorruptedObjectException(Errors.format(Errors.Keys.UnknownType_1, pt));
@@ -203,9 +205,9 @@ public abstract class AbstractFeature im
         if (pt instanceof DefaultAttributeType<?>) {
             return AbstractAttribute.create((DefaultAttributeType<?>) pt);
         } else if (pt instanceof DefaultAssociationRole) {
-            return new SingletonAssociation((DefaultAssociationRole) pt);
+            return AbstractAssociation.create((DefaultAssociationRole) pt);
         } else {
-            throw new IllegalArgumentException(unsupportedPropertyType(pt.getName()));
+            throw unsupportedPropertyType(pt.getName());
         }
     }
 
@@ -224,7 +226,7 @@ public abstract class AbstractFeature im
         } else if (pt instanceof DefaultAssociationRole) {
             return null; // No default value for associations.
         } else {
-            throw new IllegalArgumentException(unsupportedPropertyType(pt.getName()));
+            throw unsupportedPropertyType(pt.getName());
         }
     }
 
@@ -233,7 +235,7 @@ public abstract class AbstractFeature im
      */
     private static <V> Object getDefaultValue(final DefaultAttributeType<V> attribute)
{
         final V defaultValue = attribute.getDefaultValue();
-        if (attribute.getMaximumOccurs() <= 1) {
+        if (Field.isSingleton(attribute.getMaximumOccurs())) {
             return defaultValue;
         } else {
             // Following is for compliance with getPropertyValue(String) method contract
- see its javadoc.
@@ -289,8 +291,16 @@ public abstract class AbstractFeature im
      * Returns the value of the given attribute, as a singleton or as a collection depending
      * on the maximum number of occurrences.
      */
-    static Object getAttributeValue(final AbstractAttribute<?> attribute) {
-        return attribute.getType().getMaximumOccurs() <= 1 ? attribute.getValue() : attribute.getValues();
+    static Object getAttributeValue(final AbstractAttribute<?> property) {
+        return Field.isSingleton(property.getType().getMaximumOccurs()) ? property.getValue()
: property.getValues();
+    }
+
+    /**
+     * Returns the value of the given association, as a singleton or as a collection depending
+     * on the maximum number of occurrences.
+     */
+    static Object getAssociationValue(final AbstractAssociation property) {
+        return Field.isSingleton(property.getRole().getMaximumOccurs()) ? property.getValue()
: property.getValues();
     }
 
     /**
@@ -300,10 +310,9 @@ public abstract class AbstractFeature im
         if (property instanceof AbstractAttribute<?>) {
             setAttributeValue((AbstractAttribute<?>) property, value);
         } else if (property instanceof AbstractAssociation) {
-            ArgumentChecks.ensureCanCast("value", AbstractFeature.class, value);
-            setAssociationValue((AbstractAssociation) property, (AbstractFeature) value);
+            setAssociationValue((AbstractAssociation) property, value);
         } else {
-            throw new IllegalArgumentException(unsupportedPropertyType(property.getName()));
+            throw unsupportedPropertyType(property.getName());
         }
     }
 
@@ -331,8 +340,7 @@ public abstract class AbstractFeature im
                     } while ((element = it.next()) == null || base.isInstance(element));
                     // Found an illegal value. Exeption is thrown below.
                 }
-                throw new ClassCastException(Errors.format(Errors.Keys.IllegalPropertyClass_2,
-                        pt.getName(), element.getClass())); // 'element' can not be null
here.
+                throw illegalValueClass(attribute.getName(), element); // 'element' can not
be null here.
             }
         }
         ((AbstractAttribute) attribute).setValue(value);
@@ -342,17 +350,25 @@ public abstract class AbstractFeature im
      * Sets the association value after verification of its type.
      * For a more exhaustive validation, use {@link Validator} instead.
      */
-    private static void setAssociationValue(final AbstractAssociation association, final
AbstractFeature value) {
+    @SuppressWarnings("unchecked")
+    private static void setAssociationValue(final AbstractAssociation association, final
Object value) {
         if (value != null) {
-            final DefaultAssociationRole pt = association.getRole();
-            final DefaultFeatureType base = pt.getValueType();
-            final DefaultFeatureType actual = value.getType();
-            if (!base.maybeAssignableFrom(actual)) {
-                throw new IllegalArgumentException(Errors.format(Errors.Keys.IllegalPropertyClass_2,
-                        pt.getName(), actual.getName()));
+            final DefaultAssociationRole role = association.getRole();
+            final DefaultFeatureType base = role.getValueType();
+            if (value instanceof AbstractFeature) {
+                final DefaultFeatureType actual = ((AbstractFeature) value).getType();
+                if (!base.maybeAssignableFrom(actual)) {
+                    throw illegalPropertyType(role.getName(), actual.getName());
+                }
+            } else if (value instanceof Collection<?>) {
+                verifyAssociationValues(role, (Collection<?>) value);
+                association.setValues((Collection<? extends AbstractFeature>) value);
+                return; // Skip the setter at the end of this method.
+            } else {
+                throw illegalValueClass(association.getName(), value);
             }
         }
-        association.setValue(value);
+        association.setValue((AbstractFeature) value);
     }
 
     /**
@@ -384,16 +400,15 @@ public abstract class AbstractFeature im
      * @param property The property to verify.
      */
     final void verifyPropertyType(final String name, final Property property) {
-        final PropertyType type;
+        final PropertyType type, base = getPropertyType(name);
         if (property instanceof AbstractAttribute<?>) {
             type = ((AbstractAttribute<?>) property).getType();
         } else if (property instanceof AbstractAssociation) {
             type = ((AbstractAssociation) property).getRole();
         } else {
-            throw new IllegalArgumentException(Errors.format(
-                    Errors.Keys.IllegalArgumentClass_2, "property", property.getClass()));
+            throw illegalPropertyType(base.getName(), property.getClass());
         }
-        if (type != getPropertyType(name)) {
+        if (type != base) {
             throw new IllegalArgumentException(Errors.format(Errors.Keys.MismatchedPropertyType_1,
name));
         }
     }
@@ -410,14 +425,10 @@ public abstract class AbstractFeature im
             }
         } else if (pt instanceof DefaultAssociationRole) {
             if (value != null) {
-                if (!(value instanceof AbstractFeature)) {
-                    throw new ClassCastException(Errors.format(Errors.Keys.IllegalPropertyClass_2,
-                            name, value.getClass()));
-                }
-                return verifyAssociationValue((DefaultAssociationRole) pt, (AbstractFeature)
value);
+                return verifyAssociationValue((DefaultAssociationRole) pt, value);
             }
         } else {
-            throw new IllegalArgumentException(unsupportedPropertyType(pt.getName()));
+            throw unsupportedPropertyType(pt.getName());
         }
         return value;
     }
@@ -429,23 +440,19 @@ public abstract class AbstractFeature im
      *   <li>May be a singleton,  in which case the value class is verified.</li>
      *   <li>May be a collection, in which case the class each elements in the collection
is verified.</li>
      * </ul>
+     *
+     * @param value The value, which shall be non-null.
      */
     private static <T> Object verifyAttributeValue(final DefaultAttributeType<T>
type, final Object value) {
         final Class<T> valueClass = type.getValueClass();
-        final boolean isMultiValued = type.getMaximumOccurs() > 1;
+        final boolean isSingleton = Field.isSingleton(type.getMaximumOccurs());
         if (valueClass.isInstance(value)) {
-            if (isMultiValued) {
-                return singleton(valueClass, type.getMinimumOccurs(), value);
-            }
+            return isSingleton ? value : singletonList(valueClass, type.getMinimumOccurs(),
value);
+        } else if (!isSingleton && value instanceof Collection<?>) {
+            return CheckedArrayList.castOrCopy((Collection<?>) value, valueClass);
         } else {
-            if (isMultiValued && value instanceof Collection<?>) {
-                return CheckedArrayList.castOrCopy((Collection<?>) value, valueClass);
-            } else {
-                throw new ClassCastException(Errors.format(Errors.Keys.IllegalPropertyClass_2,
-                        type.getName(), value.getClass()));
-            }
+            throw illegalValueClass(type.getName(), value);
         }
-        return value;
     }
 
     /**
@@ -453,32 +460,85 @@ public abstract class AbstractFeature im
      * An association:
      * <ul>
      *   <li>May be a singleton,  in which case the feature type is verified.</li>
+     *   <li>May be a collection, in which case the class each elements in the collection
is verified.</li>
      * </ul>
+     *
+     * @param value The value, which shall be non-null.
      */
-    private static Object verifyAssociationValue(final DefaultAssociationRole role, final
AbstractFeature value) {
-        final DefaultFeatureType valueType = value.getType();
-        if (!role.getValueType().maybeAssignableFrom(valueType)) {
-            throw new IllegalArgumentException(Errors.format(Errors.Keys.IllegalPropertyClass_2,
-                    role.getName(), valueType.getName()));
+    private static Object verifyAssociationValue(final DefaultAssociationRole role, final
Object value) {
+        final boolean isSingleton = Field.isSingleton(role.getMaximumOccurs());
+        if (value instanceof AbstractFeature) {
+            /*
+             * If the user gave us a single value, first verify its validity.
+             * Then wrap it in a list of 1 element if this property is multi-valued.
+             */
+            final DefaultFeatureType valueType = ((AbstractFeature) value).getType();
+            if (role.getValueType().maybeAssignableFrom(valueType)) {
+                return isSingleton ? value : singletonList(AbstractFeature.class, role.getMinimumOccurs(),
value);
+            } else {
+                throw illegalPropertyType(role.getName(), valueType.getName());
+            }
+        } else if (!isSingleton && value instanceof Collection<?>) {
+            verifyAssociationValues(role, (Collection<?>) value);
+            return CheckedArrayList.castOrCopy((Collection<?>) value, AbstractFeature.class);
+        } else {
+            throw illegalValueClass(role.getName(), value);
+        }
+    }
+
+    /**
+     * Verifies if all values in the given collection are valid instances of feature for
the given association role.
+     */
+    private static void verifyAssociationValues(final DefaultAssociationRole role, final
Collection<?> values) {
+        final DefaultFeatureType base = role.getValueType();
+        int index = 0;
+        for (final Object value : values) {
+            ArgumentChecks.ensureNonNullElement("values", index, value);
+            if (!(value instanceof AbstractFeature)) {
+                throw illegalValueClass(role.getName(), value);
+            }
+            final DefaultFeatureType type = ((AbstractFeature) value).getType();
+            if (!base.maybeAssignableFrom(type)) {
+                throw illegalPropertyType(role.getName(), type.getName());
+            }
+            index++;
         }
-        return value;
     }
 
     /**
      * Creates a collection which will initially contain only the given value.
+     * At the difference of {@link Collections#singletonList(Object)}, this method returns
a modifiable list.
      */
     @SuppressWarnings("unchecked")
-    private static <V> Collection<V> singleton(final Class<V> valueClass,
final int minimumOccurs, final Object value) {
+    private static <V> Collection<V> singletonList(final Class<V> valueClass,
final int minimumOccurs, final Object value) {
         final CheckedArrayList<V> values = new CheckedArrayList<>(valueClass,
Math.max(minimumOccurs, 4));
         values.add((V) value); // Type will be checked by CheckedArrayList.
         return values;
     }
 
     /**
-     * Returns the exception message for a property type which neither an attribute or an
association.
+     * Returns the exception for a property type which neither an attribute or an association.
+     * This method is invoked after a {@link PropertyType} has been found for the user-supplied
name,
+     * but that property can not be stored in a {@link Property} instance.
+     */
+    static IllegalArgumentException unsupportedPropertyType(final GenericName name) {
+        return new IllegalArgumentException(Errors.format(Errors.Keys.CanNotInstantiate_1,
name));
+    }
+
+    /**
+     * Returns the exception for a property value of wrong Java class.
+     *
+     * @param value The value, which shall be non-null.
+     */
+    private static ClassCastException illegalValueClass(final GenericName name, final Object
value) {
+        return new ClassCastException(Errors.format(Errors.Keys.IllegalPropertyClass_2, name,
value.getClass()));
+    }
+
+    /**
+     * Returns the exception for a property value (usually a feature) of wrong type.
      */
-    static String unsupportedPropertyType(final GenericName name) {
-        return Errors.format(Errors.Keys.CanNotInstantiate_1, name);
+    private static IllegalArgumentException illegalPropertyType(final GenericName name, final
Object value) {
+        return new IllegalArgumentException(Errors.format(Errors.Keys.IllegalPropertyClass_2,
name, value));
     }
 
     /**

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=1597095&r1=1597094&r2=1597095&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] Fri May 23 13:45:40 2014
@@ -165,9 +165,9 @@ final class DenseFeature extends Abstrac
                 } else if (element instanceof AbstractAttribute<?>) {
                     return getAttributeValue((AbstractAttribute<?>) element);
                 } else if (element instanceof AbstractAssociation) {
-                    return ((AbstractAssociation) element).getValue();
+                    return getAssociationValue((AbstractAssociation) element);
                 } else {
-                    throw new IllegalArgumentException(unsupportedPropertyType(((Property)
element).getName()));
+                    throw unsupportedPropertyType(((Property) element).getName());
                 }
             }
         }

Modified: sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/Field.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/Field.java?rev=1597095&r1=1597094&r2=1597095&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/Field.java [UTF-8]
(original)
+++ sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/Field.java [UTF-8]
Fri May 23 13:45:40 2014
@@ -39,6 +39,17 @@ abstract class Field<V> extends Property
     }
 
     /**
+     * Returns {@code true} if an attribute type or association role having the given
+     * maximum number of occurrences should be treated as a singleton.
+     *
+     * This method gives us a simple keyword to search for every places in the code
+     * where a decision regarding "singleton versus multi-valued" is made.
+     */
+    static boolean isSingleton(final int maximumOccurs) {
+        return maximumOccurs <= 1;
+    }
+
+    /**
      * Returns the field feature or attribute value, or {@code null} if none.
      *
      * @return The feature or attribute value (may be {@code null}).
@@ -69,7 +80,7 @@ abstract class Field<V> extends Property
     public abstract void setValue(final V value);
 
     /**
-     * Set the features or attribute values. All previous values are replaced by the given
collection.
+     * Sets the features or 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>

Copied: sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/MultiValuedAssociation.java
(from r1596975, sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/MultiValuedAttribute.java)
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/MultiValuedAssociation.java?p2=sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/MultiValuedAssociation.java&p1=sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/MultiValuedAttribute.java&r1=1596975&r2=1597095&rev=1597095&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/MultiValuedAttribute.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/MultiValuedAssociation.java
[UTF-8] Fri May 23 13:45:40 2014
@@ -17,91 +17,77 @@
 package org.apache.sis.feature;
 
 import java.util.Collection;
-import java.lang.reflect.Field;
 import org.apache.sis.internal.util.CheckedArrayList;
 import org.apache.sis.util.ArgumentChecks;
 import org.apache.sis.util.resources.Errors;
 
 
 /**
- * An instance of an {@linkplain DefaultAttributeType attribute type} containing an arbitrary
amount of values.
+ * An instance of an {@linkplain DefaultAssociationRole association role} containing an arbitrary
amount of values.
  *
- * <div class="note"><b>Note:</b> in the common case where the {@linkplain
DefaultAttributeType attribute type}
- * restricts the cardinality to [0 … 1], the {@link SingletonAttribute} implementation
consumes less memory.</div>
+ * <div class="note"><b>Note:</b> in the common case where the {@linkplain
DefaultAssociationRole association role}
+ * restricts the cardinality to [0 … 1], the {@link SingletonAssociation} implementation
consumes less memory.</div>
  *
  * {@section Limitations}
  * <ul>
- *   <li><b>Multi-threading:</b> {@code MultiValuedAttribute} instances
are <strong>not</strong> thread-safe.
+ *   <li><b>Multi-threading:</b> {@code MultiValuedAssociation} 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 <V> The type of the attribute values.
- *
- * @author  Johann Sorel (Geomatys)
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.5
  * @version 0.5
  * @module
  *
- * @see DefaultAttributeType
+ * @see DefaultAssociationRole
  */
-final class MultiValuedAttribute<V> extends AbstractAttribute<V> implements Cloneable
{
+final class MultiValuedAssociation extends AbstractAssociation implements Cloneable {
     /**
      * For cross-version compatibility.
      */
-    private static final long serialVersionUID = -7824265855672575215L;
+    private static final long serialVersionUID = 5089428248556035466L;
 
     /**
-     * The attribute values.
+     * The association values.
      */
-    private final CheckedArrayList<V> values;
+    private CheckedArrayList<AbstractFeature> values;
 
     /**
-     * Creates a new attribute of the given type initialized to the
-     * {@linkplain DefaultAttributeType#getDefaultValue() default value}.
+     * Creates a new association of the given role.
      *
-     * @param type Information about the attribute (base Java class, domain of values, <i>etc.</i>).
+     * @param role Information about the association.
      */
-    public MultiValuedAttribute(final DefaultAttributeType<V> type) {
-        super(type);
-        values = new CheckedArrayList<>(type.getValueClass());
-        final V value = type.getDefaultValue();
-        if (value != null) {
-            values.add(value);
-        }
+    public MultiValuedAssociation(final DefaultAssociationRole role) {
+        super(role);
+        values = new CheckedArrayList<>(AbstractFeature.class);
     }
 
     /**
-     * Creates a new attribute of the given type initialized to the given values.
-     * Note that a {@code null} value may not be the same as the default value.
+     * Creates a new association of the given role initialized to the given values.
      *
-     * @param type   Information about the attribute (base Java class, domain of values,
<i>etc.</i>).
+     * @param role   Information about the association.
      * @param values The initial values, or {@code null} for initializing to an empty list.
      */
-    @SuppressWarnings("unchecked")
-    MultiValuedAttribute(final DefaultAttributeType<V> type, final Object values) {
-        super(type);
-        final Class<V> valueClass = type.getValueClass();
+    MultiValuedAssociation(final DefaultAssociationRole role, final Object values) {
+        super(role);
         if (values == null) {
-            this.values = new CheckedArrayList<>(valueClass);
-        } else if (((CheckedArrayList<?>) values).getElementType() == valueClass) {
-            this.values = (CheckedArrayList<V>) values;
+            this.values = new CheckedArrayList<>(AbstractFeature.class);
         } else {
-            throw new ClassCastException();
+            this.values = CheckedArrayList.castOrCopy((CheckedArrayList<?>) values,
AbstractFeature.class);
         }
     }
 
     /**
-     * Returns the attribute value, or {@code null} if none.
+     * Returns the feature, or {@code null} if none.
      *
-     * @return The attribute value (may be {@code null}).
-     * @throws IllegalStateException if this attribute contains more than one value.
+     * @return The feature (may be {@code null}).
+     * @throws IllegalStateException if this association contains more than one value.
      */
     @Override
-    public V getValue() {
+    public AbstractFeature getValue() {
         switch (values.size()) {
             case 0:  return null;
             case 1:  return values.get(0);
@@ -110,79 +96,78 @@ final class MultiValuedAttribute<V> exte
     }
 
     /**
-     * Returns all attribute values, or an empty collection if none.
+     * Returns all features, 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.
+     * will be reflected immediately in this {@code Association} instance, and conversely.
      *
-     * @return The attribute values in a <cite>live</cite> collection.
+     * @return The features in a <cite>live</cite> collection.
      */
     @Override
-    public Collection<V> getValues() {
+    public Collection<AbstractFeature> getValues() {
         return values;
     }
 
     /**
-     * Sets the attribute value.
+     * Sets the feature.
      *
-     * @param value The new value, or {@code null} for removing all values from this attribute.
+     * @param value The new value, or {@code null} for removing all values from this association.
      */
     @Override
-    public void setValue(final V value) {
+    public void setValue(final AbstractFeature value) {
         values.clear();
         if (value != null) {
+            ensureValid(role.getValueType(), value.getType());
             values.add(value);
         }
     }
 
     /**
-     * Set the attribute values. All previous values are replaced by the given collection.
+     * Sets the feature values. All previous values are replaced by the given collection.
      *
      * @param values The new values.
      */
     @Override
-    public void setValues(final Collection<? extends V> values) {
+    public void setValues(final Collection<? extends AbstractFeature> values) {
         ArgumentChecks.ensureNonNull("values", values);
+        final DefaultFeatureType base = role.getValueType();
         this.values.clear();
-        this.values.addAll(values);
+        for (final AbstractFeature value : values) {
+            ensureValid(base, value.getType());
+            this.values.add(value);
+        }
     }
 
     /**
-     * Returns a copy of this attribute.
+     * Returns a copy of this association.
      * The default implementation returns a <em>shallow</em> copy:
-     * the attribute {@linkplain #getValues() values} are <strong>not</strong>
cloned.
+     * the association {@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.
+     * @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 attribute values.
+     *         for example on attempt to clone the association values.
      */
     @Override
     @SuppressWarnings("unchecked")
-    public MultiValuedAttribute<V> clone() throws CloneNotSupportedException {
-        final MultiValuedAttribute<V> clone = (MultiValuedAttribute<V>) super.clone();
-        try {
-            final Field field = MultiValuedAttribute.class.getDeclaredField("values");
-            field.setAccessible(true);
-            field.set(clone, clone.values.clone());
-        } catch (ReflectiveOperationException e) {
-            throw new AssertionError(e);
-        }
+    public MultiValuedAssociation clone() throws CloneNotSupportedException {
+        final MultiValuedAssociation clone = (MultiValuedAssociation) super.clone();
+        clone.values = (CheckedArrayList<AbstractFeature>) clone.values.clone();
         return clone;
     }
 
     /**
-     * Returns a hash code value for this attribute type.
+     * Returns a hash code value for this association.
      *
      * @return A hash code value.
      */
     @Override
     public int hashCode() {
-        return type.hashCode() + values.hashCode();
+        return role.hashCode() + values.hashCode();
     }
 
     /**
-     * Compares this attribute with the given object for equality.
+     * Compares this association with the given object for equality.
      *
      * @return {@code true} if both objects are equal.
      */
@@ -191,9 +176,9 @@ final class MultiValuedAttribute<V> exte
         if (obj == this) {
             return true;
         }
-        if (obj instanceof MultiValuedAttribute<?>) {
-            final MultiValuedAttribute<?> that = (MultiValuedAttribute<?>) obj;
-            return type.equals(that.type) && values.equals(that.values);
+        if (obj instanceof MultiValuedAssociation) {
+            final MultiValuedAssociation that = (MultiValuedAssociation) obj;
+            return role.equals(that.role) && values.equals(that.values);
         }
         return false;
     }

Modified: sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/MultiValuedAttribute.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/MultiValuedAttribute.java?rev=1597095&r1=1597094&r2=1597095&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/MultiValuedAttribute.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/MultiValuedAttribute.java
[UTF-8] Fri May 23 13:45:40 2014
@@ -135,7 +135,7 @@ final class MultiValuedAttribute<V> exte
     }
 
     /**
-     * Set the attribute values. All previous values are replaced by the given collection.
+     * Sets the attribute values. All previous values are replaced by the given collection.
      *
      * @param values The new values.
      */
@@ -172,7 +172,7 @@ final class MultiValuedAttribute<V> exte
     }
 
     /**
-     * Returns a hash code value for this attribute type.
+     * Returns a hash code value for this attribute.
      *
      * @return A hash code value.
      */

Modified: sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/SingletonAssociation.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/SingletonAssociation.java?rev=1597095&r1=1597094&r2=1597095&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/SingletonAssociation.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/SingletonAssociation.java
[UTF-8] Fri May 23 13:45:40 2014
@@ -51,22 +51,24 @@ final class SingletonAssociation extends
     private AbstractFeature value;
 
     /**
-     * Creates a new association of the given type.
+     * Creates a new association of the given role.
      *
      * @param role Information about the association.
      */
     public SingletonAssociation(final DefaultAssociationRole role) {
         super(role);
+        assert isSingleton(role.getMaximumOccurs());
     }
 
     /**
-     * Creates a new association of the given type initialized to the given value.
+     * Creates a new association of the given role initialized to the given value.
      *
      * @param role  Information about the association.
      * @param value The initial value (may be {@code null}).
      */
     SingletonAssociation(final DefaultAssociationRole role, final AbstractFeature value)
{
         super(role);
+        assert isSingleton(role.getMaximumOccurs());
         this.value = value;
         if (value != null) {
             ensureValid(role.getValueType(), value.getType());

Modified: sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/SingletonAttribute.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/SingletonAttribute.java?rev=1597095&r1=1597094&r2=1597095&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/SingletonAttribute.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/SingletonAttribute.java
[UTF-8] Fri May 23 13:45:40 2014
@@ -61,7 +61,7 @@ final class SingletonAttribute<V> extend
      */
     public SingletonAttribute(final DefaultAttributeType<V> type) {
         super(type);
-        assert type.getMaximumOccurs() <= 1;
+        assert isSingleton(type.getMaximumOccurs());
         value = type.getDefaultValue();
     }
 
@@ -74,7 +74,7 @@ final class SingletonAttribute<V> extend
      */
     SingletonAttribute(final DefaultAttributeType<V> type, final Object value) {
         super(type);
-        assert type.getMaximumOccurs() <= 1;
+        assert isSingleton(type.getMaximumOccurs());
         this.value = type.getValueClass().cast(value);
     }
 
@@ -116,7 +116,7 @@ final class SingletonAttribute<V> extend
     }
 
     /**
-     * Returns a hash code value for this attribute type.
+     * Returns a hash code value for this attribute.
      *
      * @return A hash code value.
      */

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=1597095&r1=1597094&r2=1597095&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] Fri May 23 13:45:40 2014
@@ -179,9 +179,9 @@ final class SparseFeature extends Abstra
             } else if (element instanceof AbstractAttribute<?>) {
                 return getAttributeValue((AbstractAttribute<?>) element);
             } else if (element instanceof AbstractAssociation) {
-                return ((AbstractAssociation) element).getValue();
+                return getAssociationValue((AbstractAssociation) element);
             } else if (valuesKind == PROPERTIES) {
-                throw new IllegalArgumentException(unsupportedPropertyType(((Property) element).getName()));
+                throw unsupportedPropertyType(((Property) element).getName());
             } else {
                 throw new CorruptedObjectException(String.valueOf(getName()));
             }

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=1597095&r1=1597094&r2=1597095&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] Fri May 23 13:45:40 2014
@@ -72,10 +72,10 @@
  * {@code      ├─} {@linkplain org.apache.sis.feature.DefaultAssociationRole  Feature
association role}<br>
  * {@code      └─} {@linkplain org.apache.sis.feature.DefaultOperation        Operation}<br>
  * </td><td class="sep" style="width: 50%; white-space: nowrap">
- *             {@linkplain org.apache.sis.feature.AbstractFeature     Feature}<br>
+ *             {@linkplain org.apache.sis.feature.AbstractFeature     Feature}          
  (<cite>sparse</cite> or <cite>dense</cite>)<br>
  *                                                                    Property<br>
- * {@code  ├─} {@linkplain org.apache.sis.feature.AbstractAttribute   Attribute}<br>
- * {@code  └─} {@linkplain org.apache.sis.feature.AbstractAssociation Feature association}<br>
+ * {@code  ├─} {@linkplain org.apache.sis.feature.AbstractAttribute   Attribute}   
       (<cite>singleton</cite> or <cite>multi-valued</cite>)<br>
+ * {@code  └─} {@linkplain org.apache.sis.feature.AbstractAssociation Feature association}
(<cite>singleton</cite> or <cite>multi-valued</cite>)<br>
  * </td></tr></table>
  *
  * @author  Travis L. Pinney

Modified: sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/DefaultAssociationRoleTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/DefaultAssociationRoleTest.java?rev=1597095&r1=1597094&r2=1597095&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/DefaultAssociationRoleTest.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/DefaultAssociationRoleTest.java
[UTF-8] Fri May 23 13:45:40 2014
@@ -35,11 +35,12 @@ import static org.apache.sis.test.Assert
 @DependsOn(DefaultFeatureTypeTest.class)
 public final strictfp class DefaultAssociationRoleTest extends TestCase {
     /**
-     * Creates an association.
+     * Creates an association to a twin town. We arbitrarily fix the maximum number
+     * of occurrences to 1, even if in reality some cities have many twin towns.
      */
     static DefaultAssociationRole twinTown() {
         return new DefaultAssociationRole(singletonMap(DefaultAssociationRole.NAME_KEY, "twin
town"),
-                DefaultFeatureTypeTest.city(), 0, Integer.MAX_VALUE);
+                DefaultFeatureTypeTest.city(), 0, 1);
     }
 
     /**

Modified: sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/FeatureFormatTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/FeatureFormatTest.java?rev=1597095&r1=1597094&r2=1597095&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/FeatureFormatTest.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/FeatureFormatTest.java
[UTF-8] Fri May 23 13:45:40 2014
@@ -71,7 +71,7 @@ public final strictfp class FeatureForma
                 "├────────────┼─────────┼─────────────┼───────────┤\n"
+
                 "│ city       │ String  │ [1 … 1]     │ Paderborn │\n" +
                 "│ population │ Integer │ [1 … 1]     │ 143,174   │\n" +
-                "│ twin town  │ City    │ [0 … ∞]     │ Le Mans   │\n" +
+                "│ twin town  │ City    │ [0 … 1]     │ Le Mans   │\n" +
                 "└────────────┴─────────┴─────────────┴───────────┘\n",
text);
     }
 }

Modified: sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/SingletonAssociationTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/SingletonAssociationTest.java?rev=1597095&r1=1597094&r2=1597095&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/SingletonAssociationTest.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/SingletonAssociationTest.java
[UTF-8] Fri May 23 13:45:40 2014
@@ -58,8 +58,8 @@ public final strictfp class SingletonAss
     @Test
     public void testWrongValue() {
         final AbstractAssociation association  = twinTown();
-        final PropertyType       population   = association.getRole().getValueType().getProperty("population");
-        final AbstractFeature    otherFeature = new DefaultFeatureType(
+        final PropertyType        population   = association.getRole().getValueType().getProperty("population");
+        final AbstractFeature     otherFeature = new DefaultFeatureType(
                 singletonMap(DefaultFeatureType.NAME_KEY, "Population"), false, null, population).newInstance();
         try {
             association.setValue(otherFeature);



Mime
View raw message