sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1519807 - in /sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing: ./ datum/
Date Tue, 03 Sep 2013 19:35:48 GMT
Author: desruisseaux
Date: Tue Sep  3 19:35:48 2013
New Revision: 1519807

URL: http://svn.apache.org/r1519807
Log:
Revisit the hashCode(...) method, since we had an inconsistency with equals(...) in the way
to take in account which interface is implemented.
While fixing the inconsistency, we opportunistically lined-up the API with the equals(…,
ComparisonMode) one,
in the hope to be more future-proof regarding possible SIS API evolution.

Modified:
    sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/AbstractIdentifiedObject.java
    sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/AbstractReferenceSystem.java
    sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/IdentifiedObjects.java
    sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/AbstractDatum.java
    sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultEngineeringDatum.java
    sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultImageDatum.java
    sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultPrimeMeridian.java

Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/AbstractIdentifiedObject.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/AbstractIdentifiedObject.java?rev=1519807&r1=1519806&r2=1519807&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/AbstractIdentifiedObject.java
[UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/AbstractIdentifiedObject.java
[UTF-8] Tue Sep  3 19:35:48 2013
@@ -39,7 +39,6 @@ import org.opengis.referencing.Identifie
 import org.opengis.referencing.ReferenceIdentifier;
 import org.apache.sis.io.wkt.FormattableObject;
 import org.apache.sis.xml.Namespaces;
-import org.apache.sis.util.Classes;
 import org.apache.sis.util.Immutable;
 import org.apache.sis.util.ThreadSafe;
 import org.apache.sis.util.Deprecable;
@@ -452,16 +451,18 @@ public class AbstractIdentifiedObject ex
 
     /**
      * Returns {@code true} if either the {@linkplain #getName() primary name} or at least
-     * one {@linkplain #getAlias alias} matches the specified string.
-     * This method performs the search in the following order, regardless of any authority:
+     * one {@linkplain #getAlias() alias} matches the specified string.
+     * This method returns {@code true} if the given name is equal to one of the following
names,
+     * regardless of any authority:
      *
      * <ul>
-     *   <li>The {@linkplain #getName() primary name} of this object</li>
-     *   <li>The {@linkplain ScopedName fully qualified name} of an alias</li>
-     *   <li>The {@linkplain LocalName local name} of an alias</li>
+     *   <li>The {@linkplain #getName() primary name} of this object.</li>
+     *   <li>The {@linkplain org.opengis.util.GenericName#toFullyQualifiedName() fully
qualified name} of an alias.</li>
+     *   <li>The {@linkplain org.opengis.util.ScopedName#tail() tail} of an alias.</li>
+     *   <li>The tail of the previous tail, recursively up to the {@linkplain org.opengis.util.ScopedName#tip()
tip}.</li>
      * </ul>
      *
-     * @param  name The name to compare.
+     * @param  name The name to compare with the object name or aliases.
      * @return {@code true} if the primary name of at least one alias matches the specified
{@code name}.
      *
      * @see IdentifiedObjects#nameMatches(IdentifiedObject, String)
@@ -471,25 +472,6 @@ public class AbstractIdentifiedObject ex
     }
 
     /**
-     * Compares the specified object with this object for equality.
-     * This method is implemented as below (omitting assertions):
-     *
-     * {@preformat java
-     *     return equals(other, ComparisonMode.STRICT);
-     * }
-     *
-     * @param  object The other object (may be {@code null}).
-     * @return {@code true} if both objects are equal.
-     */
-    @Override
-    public final boolean equals(final Object object) {
-        final boolean eq = equals(object, ComparisonMode.STRICT);
-        // If objects are equal, then they must have the same hash code value.
-        assert !eq || hashCode() == object.hashCode() : this;
-        return eq;
-    }
-
-    /**
      * Compares this object with the specified object for equality.
      * The strictness level is controlled by the second argument:
      *
@@ -498,9 +480,9 @@ public class AbstractIdentifiedObject ex
      *       are compared including {@linkplain #getName() name}, {@linkplain #getRemarks()
remarks},
      *       {@linkplain #getIdentifiers() identifiers code}, <i>etc.</i></li>
      *   <li>If {@code mode} is {@link ComparisonMode#IGNORE_METADATA IGNORE_METADATA},
-     *       then this method compare only the properties needed for computing transformations.
-     *       In other words, {@code sourceCS.equals(targetCS, IGNORE_METADATA)} returns {@code
true}
-     *       if the transformation from {@code sourceCS} to {@code targetCS} is likely to
be the
+     *       then this method compares only the properties needed for computing transformations.
+     *       In other words, {@code sourceCRS.equals(targetCRS, IGNORE_METADATA)} returns
{@code true}
+     *       if the transformation from {@code sourceCRS} to {@code targetCRS} is likely
to be the
      *       identity transform, no matter what {@link #getName()} said.</li>
      * </ul>
      *
@@ -517,6 +499,9 @@ public class AbstractIdentifiedObject ex
      *         {@link ComparisonMode#IGNORE_METADATA IGNORE_METADATA} for comparing only
properties
      *         relevant to transformations.
      * @return {@code true} if both objects are equal.
+     *
+     * @see #hashCode(ComparisonMode)
+     * @see org.apache.sis.util.Utilities#deepEquals(Object, Object, ComparisonMode)
      */
     @Override
     public boolean equals(final Object object, final ComparisonMode mode) {
@@ -575,51 +560,88 @@ public class AbstractIdentifiedObject ex
     }
 
     /**
-     * Returns a hash value for this identified object.
-     * This method invokes {@link #computeHashCode()} when first needed and caches the value
for future invocations.
-     * Subclasses shall override {@code computeHashCode()} instead than this method.
+     * Computes a hash value consistent with the given comparison mode.
+     * This method accepts only the following enumeration values:
      *
-     * {@section Implementation specific feature}
-     * In the Apache SIS implementation, the {@linkplain #getName() name}, {@linkplain #getIdentifiers()
identifiers}
-     * and {@linkplain #getRemarks() remarks} are not used for hash code computation.
-     * Consequently two identified objects will return the same hash value if they are equal
in the sense of
-     * <code>{@linkplain #equals(Object, ComparisonMode) equals}(…, {@linkplain ComparisonMode#IGNORE_METADATA})</code>.
+     * <ul>
+     *   <li>{@link ComparisonMode#STRICT} (the default): this method may use any property,
+     *       including implementation-specific ones if any, at implementation choice.</li>
+     *   <li>{@link ComparisonMode#BY_CONTRACT}: this method can use any property defined
+     *       in the implemented interface (typically a GeoAPI interface).</li>
+     *   <li>{@link ComparisonMode#IGNORE_METADATA}: this method ignores the metadata
that do not affect
+     *       coordinate operations. By default, the ignored properties are the {@linkplain
#getName() name},
+     *       {@linkplain #getIdentifiers() identifiers} and {@linkplain #getRemarks() remarks}.
+     *       However subclasses may ignore a different list of properties.</li>
+     * </ul>
+     *
+     * In the later case, two identified objects will return the same hash value if they
are equal in the sense of
+     * <code>{@linkplain #equals(Object, ComparisonMode) equals}(object, {@linkplain
ComparisonMode#IGNORE_METADATA})</code>.
      * This feature allows users to implement metadata-insensitive {@link java.util.HashMap}.
      *
+     * @param  mode Specifies the set of properties that can be used for hash code computation.
      * @return The hash code value. This value may change between different execution of
the Apache SIS library.
+     * @throws IllegalArgumentException If the given {@code mode} is not one of {@code STRICT},
{@code BY_CONTRACT}
+     *         or {@code IGNORE_METADATA} enumeration values.
      */
-    @Override
-    public final int hashCode() { // No need to synchronize; ok if invoked twice.
-        int hash = hashCode;
-        if (hash == 0) {
-            hash = computeHashCode();
-            if (hash == 0) {
-                hash = -1;
+    public int hashCode(final ComparisonMode mode) throws IllegalArgumentException {
+        int code = (int) serialVersionUID;
+        switch (mode) {
+            case STRICT: {
+                code ^= Objects.hash(name, nonNull(alias), nonNull(identifiers), remarks);
+                break;
+            }
+            case BY_CONTRACT: {
+                code ^= Objects.hash(getName(), getAlias(), getIdentifiers(), getRemarks());
+                break;
+            }
+            case IGNORE_METADATA: {
+                break;
+            }
+            default: {
+                throw new IllegalArgumentException(Errors.format(Errors.Keys.IllegalArgumentValue_2,
"mode", mode));
             }
-            hashCode = hash;
         }
-        assert hash == -1 || hash == computeHashCode() : this;
-        return hash;
+        return code;
     }
 
     /**
-     * Computes a hash value for this identified object.
-     * This method is invoked by {@link #hashCode()} when first needed.
+     * Compares the specified object with this object for equality.
+     * This method is implemented as below (omitting assertions):
      *
-     * <p>The default implementation computes a code derived from the list of {@link
IdentifiedObject} interfaces
-     * implemented by this instance. The {@linkplain #getName() name}, {@linkplain #getIdentifiers()
identifiers}
-     * and {@linkplain #getRemarks() remarks} are intentionally <strong>not</strong>
used for hash code computation.
-     * See the <cite>Implementation specific feature</cite> section in {@link
#hashCode()} for more information.</p>
+     * {@preformat java
+     *     return equals(other, ComparisonMode.STRICT);
+     * }
+     *
+     * @param  object The other object (may be {@code null}).
+     * @return {@code true} if both objects are equal.
+     */
+    @Override
+    public final boolean equals(final Object object) {
+        final boolean eq = equals(object, ComparisonMode.STRICT);
+        // If objects are equal, then they must have the same hash code value.
+        assert !eq || hashCode() == object.hashCode() : this;
+        return eq;
+    }
+
+    /**
+     * Returns a hash value for this identified object.
+     * This method invokes <code>{@linkplain #hashCode(ComparisonMode) hashCode}(ComparisonMode.STRICT)</code>
+     * when first needed and caches the value for future invocations.
+     * Subclasses shall override {@link #hashCode(ComparisonMode)} instead than this method.
      *
      * @return The hash code value. This value may change between different execution of
the Apache SIS library.
      */
-    protected int computeHashCode() {
-        // Subclasses need to overrides this!!!!
-        int code = (int) serialVersionUID;
-        for (final Class<?> type : Classes.getLeafInterfaces(getClass(), IdentifiedObject.class))
{
-            // Use a plain addition in order to be insensitive to array element order.
-            code += type.hashCode();
+    @Override
+    public final int hashCode() { // No need to synchronize; ok if invoked twice.
+        int hash = hashCode;
+        if (hash == 0) {
+            hash = hashCode(ComparisonMode.STRICT);
+            if (hash == 0) {
+                hash = -1;
+            }
+            hashCode = hash;
         }
-        return code;
+        assert hash == -1 || hash == hashCode(ComparisonMode.STRICT) : this;
+        return hash;
     }
 }

Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/AbstractReferenceSystem.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/AbstractReferenceSystem.java?rev=1519807&r1=1519806&r2=1519807&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/AbstractReferenceSystem.java
[UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/AbstractReferenceSystem.java
[UTF-8] Tue Sep  3 19:35:48 2013
@@ -182,4 +182,27 @@ public class AbstractReferenceSystem ext
         }
         return false;
     }
+
+    /**
+     * Computes a hash value consistent with the given comparison mode.
+     * If the given argument is {@link ComparisonMode#IGNORE_METADATA IGNORE_METADATA}, then
the
+     * {@linkplain #getDomainOfValidity() domain of validity} and the {@linkplain #getScope()
scope}
+     * properties are ignored, in addition to other ignored properties documented in the
+     * {@linkplain AbstractIdentifiedObject#hashCode(ComparisonMode) super-class}.
+     */
+    @Override
+    public int hashCode(final ComparisonMode mode) throws IllegalArgumentException {
+        int code = super.hashCode(mode) ^ (int) serialVersionUID;
+        switch (mode) {
+            case STRICT: {
+                code ^= Objects.hash(domainOfValidity, scope);
+                break;
+            }
+            case BY_CONTRACT: {
+                code ^= Objects.hash(getDomainOfValidity(), getScope());
+                break;
+            }
+        }
+        return code;
+    }
 }

Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/IdentifiedObjects.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/IdentifiedObjects.java?rev=1519807&r1=1519806&r2=1519807&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/IdentifiedObjects.java
[UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/IdentifiedObjects.java
[UTF-8] Tue Sep  3 19:35:48 2013
@@ -291,18 +291,22 @@ public final class IdentifiedObjects ext
     /**
      * Returns {@code true} if either the {@linkplain IdentifiedObject#getName() primary
name} or
      * at least one {@linkplain IdentifiedObject#getAlias() alias} matches the specified
string.
-     * This method performs the search in the following order, regardless of any authority:
+     * This method returns {@code true} if the given name is equal to one of the following
names,
+     * regardless of any authority:
      *
-     * <ol>
+     * <ul>
      *   <li>The {@linkplain IdentifiedObject#getName() primary name} of the object.</li>
-     *   <li>The {@linkplain ScopedName fully qualified name} of an alias.</li>
-     *   <li>The {@linkplain LocalName local name} of an alias.</li>
-     * </ol>
+     *   <li>The {@linkplain GenericName#toFullyQualifiedName() fully qualified name}
of an alias.</li>
+     *   <li>The {@linkplain ScopedName#tail() tail} of an alias.</li>
+     *   <li>The tail of the previous tail, recursively up to the {@linkplain ScopedName#tip()
tip}.</li>
+     * </ul>
+     *
+     * If the given object is an instance of {@link AbstractIdentifiedObject}, then this
method delegates
+     * to its {@code nameMatches(String)} method. Otherwise this method fallbacks on a generic
algorithm.
      *
      * @param  object The object for which to check the name or alias.
-     * @param  name The name.
-     * @return {@code true} if the primary name of at least one alias
-     *         matches the specified {@code name}.
+     * @param  name The name to compare with the object name or aliases.
+     * @return {@code true} if the primary name of at least one alias matches the specified
{@code name}.
      *
      * @see AbstractIdentifiedObject#nameMatches(String)
      */

Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/AbstractDatum.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/AbstractDatum.java?rev=1519807&r1=1519806&r2=1519807&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/AbstractDatum.java
[UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/AbstractDatum.java
[UTF-8] Tue Sep  3 19:35:48 2013
@@ -249,6 +249,10 @@ public class AbstractDatum extends Abstr
 
     /**
      * Compares the specified object with this datum for equality.
+     * If the {@code mode} argument value is {@link ComparisonMode#STRICT STRICT} or
+     * {@link ComparisonMode#BY_CONTRACT BY_CONTRACT}, then all available properties are
compared including the
+     * {@linkplain #getAnchorPoint() anchor point}, {@link #getRealizationEpoch() realization
epoch},
+     * {@linkplain #getDomainOfValidity() domain of validity} and the {@linkplain #getScope()
scope}.
      *
      * @param  object The object to compare to {@code this}.
      * @param  mode {@link ComparisonMode#STRICT STRICT} for performing a strict comparison,
or
@@ -293,9 +297,35 @@ public class AbstractDatum extends Abstr
     }
 
     /**
-     * Formats the inner part of a
-     * <a href="http://www.geoapi.org/3.0/javadoc/org/opengis/referencing/doc-files/WKT.html"><cite>Well
-     * Known Text</cite> (WKT)</a> element.
+     * Computes a hash value consistent with the given comparison mode.
+     * If the given argument is {@link ComparisonMode#IGNORE_METADATA IGNORE_METADATA}, then
the
+     * {@linkplain #getAnchorPoint() anchor point}, {@link #getRealizationEpoch() realization
epoch},
+     * {@linkplain #getDomainOfValidity() domain of validity} and the {@linkplain #getScope()
scope}
+     * properties are ignored.
+     */
+    @Override
+    public int hashCode(final ComparisonMode mode) throws IllegalArgumentException {
+        int code = super.hashCode(mode) ^ (int) serialVersionUID;
+        switch (mode) {
+            case STRICT: {
+                code += Objects.hash(anchorPoint, realizationEpoch, domainOfValidity, scope);
+                break;
+            }
+            case BY_CONTRACT: {
+                code += Objects.hash(getAnchorPoint(), getRealizationEpoch(), getDomainOfValidity(),
getScope());
+                break;
+            }
+            /*
+             * The name is significant for all modes, but we nevertheless ignore it because
+             * of the way the name is compared in the equals(Object, ComparisonMode) method
+             * which make hash code computation impractical in the IGNORE_METADATA case.
+             */
+        }
+        return code;
+    }
+
+    /**
+     * Formats the inner part of a <cite>Well Known Text</cite> (WKT)</a>
element.
      *
      * {@note All subclasses will override this method, but only <code>DefaultGeodeticDatum</code>
      *        will <strong>not</strong> invoke this parent method, because horizontal
datum do not

Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultEngineeringDatum.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultEngineeringDatum.java?rev=1519807&r1=1519806&r2=1519807&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultEngineeringDatum.java
[UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultEngineeringDatum.java
[UTF-8] Tue Sep  3 19:35:48 2013
@@ -111,6 +111,14 @@ public class DefaultEngineeringDatum ext
     }
 
     /**
+     * Computes a hash value consistent with the given comparison mode.
+     */
+    @Override
+    public int hashCode(final ComparisonMode mode) throws IllegalArgumentException {
+        return super.hashCode(mode) ^ (int) serialVersionUID;
+    }
+
+    /**
      * Formats the inner part of a <cite>Well Known Text</cite> (WKT)</a>
element.
      * The keyword is "{@code LOCAL_DATUM}" in WKT 1.
      *

Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultImageDatum.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultImageDatum.java?rev=1519807&r1=1519806&r2=1519807&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultImageDatum.java
[UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultImageDatum.java
[UTF-8] Tue Sep  3 19:35:48 2013
@@ -149,12 +149,22 @@ public class DefaultImageDatum extends A
     }
 
     /**
-     * Computes a hash value for this identified object.
-     * This method is invoked by {@link #hashCode()} when first needed.
+     * Computes a hash value consistent with the given comparison mode.
      */
     @Override
-    protected int computeHashCode() {
-        return super.computeHashCode() * 31 + Objects.hashCode(pixelInCell);
+    public int hashCode(final ComparisonMode mode) throws IllegalArgumentException {
+        int code = super.hashCode(mode) ^ (int) serialVersionUID;
+        switch (mode) {
+            case STRICT: {
+                code += Objects.hashCode(pixelInCell);
+                break;
+            }
+            default: {
+                code += Objects.hashCode(getPixelInCell());
+                break;
+            }
+        }
+        return code;
     }
 
     /**

Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultPrimeMeridian.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultPrimeMeridian.java?rev=1519807&r1=1519806&r2=1519807&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultPrimeMeridian.java
[UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultPrimeMeridian.java
[UTF-8] Tue Sep  3 19:35:48 2013
@@ -241,11 +241,22 @@ public class DefaultPrimeMeridian extend
     }
 
     /**
-     * {@inheritDoc}
+     * Computes a hash value consistent with the given comparison mode.
      */
     @Override
-    protected int computeHashCode() {
-        return Numerics.hash(greenwichLongitude, super.computeHashCode());
+    public int hashCode(final ComparisonMode mode) throws IllegalArgumentException {
+        int code = super.hashCode(mode) ^ (int) serialVersionUID;
+        switch (mode) {
+            case STRICT: {
+                code += Numerics.hash(greenwichLongitude, Objects.hashCode(angularUnit));
+                break;
+            }
+            default: {
+                code += Numerics.hash(getGreenwichLongitude(), Objects.hashCode(getAngularUnit()));
+                break;
+            }
+        }
+        return code;
     }
 
     /**



Mime
View raw message