Author: tn
Date: Mon Jan 12 15:21:18 2015
New Revision: 1651115

URL: http://svn.apache.org/r1651115
Log:
[COLLECTIONS-543] AbstractCollectionDecorator does not forward equals and 
hashCode anymore to the backing collection.

Modified:
    commons/proper/collections/trunk/src/changes/changes.xml
    
commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/bag/AbstractBagDecorator.java
    
commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/bag/PredicatedBag.java
    
commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/bag/SynchronizedBag.java
    
commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/bag/TransformedBag.java
    
commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/bidimap/AbstractDualBidiMap.java
    
commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/collection/AbstractCollectionDecorator.java
    
commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/list/AbstractListDecorator.java
    
commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/list/PredicatedList.java
    
commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/list/TransformedList.java
    
commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/queue/AbstractQueueDecorator.java
    
commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/set/AbstractSetDecorator.java
    
commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/set/PredicatedSet.java
    
commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/set/TransformedSet.java
    
commons/proper/collections/trunk/src/test/java/org/apache/commons/collections4/multimap/AbstractMultiValuedMapTest.java

Modified: commons/proper/collections/trunk/src/changes/changes.xml
URL: 
http://svn.apache.org/viewvc/commons/proper/collections/trunk/src/changes/changes.xml?rev=1651115&r1=1651114&r2=1651115&view=diff
==============================================================================
--- commons/proper/collections/trunk/src/changes/changes.xml (original)
+++ commons/proper/collections/trunk/src/changes/changes.xml Mon Jan 12 
15:21:18 2015
@@ -22,6 +22,9 @@
   <body>
 
   <release version="4.1" date="TBD" description="">
+    <action issue="COLLECTIONS-543" dev="tn" type="fix">
+      "AbstractCollectionDecorator" doesn't forward equals and hashCode 
anymore.
+    </action>
     <action issue="COLLECTIONS-544" dev="tn" type="fix" due-to="Oswaldo Olivo">
       Documented runtime complexity of "CollectionUtils#retainAll(Collection, 
Collection).
     </action>

Modified: 
commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/bag/AbstractBagDecorator.java
URL: 
http://svn.apache.org/viewvc/commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/bag/AbstractBagDecorator.java?rev=1651115&r1=1651114&r2=1651115&view=diff
==============================================================================
--- 
commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/bag/AbstractBagDecorator.java
 (original)
+++ 
commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/bag/AbstractBagDecorator.java
 Mon Jan 12 15:21:18 2015
@@ -63,6 +63,16 @@ public abstract class AbstractBagDecorat
         return (Bag<E>) super.decorated();
     }
 
+    @Override
+    public boolean equals(final Object object) {
+        return object == this || decorated().equals(object);
+    }
+
+    @Override
+    public int hashCode() {
+        return decorated().hashCode();
+    }
+
     //-----------------------------------------------------------------------
 
     public int getCount(final Object object) {

Modified: 
commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/bag/PredicatedBag.java
URL: 
http://svn.apache.org/viewvc/commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/bag/PredicatedBag.java?rev=1651115&r1=1651114&r2=1651115&view=diff
==============================================================================
--- 
commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/bag/PredicatedBag.java
 (original)
+++ 
commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/bag/PredicatedBag.java
 Mon Jan 12 15:21:18 2015
@@ -87,6 +87,16 @@ public class PredicatedBag<E> extends Pr
         return (Bag<E>) super.decorated();
     }
 
+    @Override
+    public boolean equals(final Object object) {
+        return object == this || decorated().equals(object);
+    }
+
+    @Override
+    public int hashCode() {
+        return decorated().hashCode();
+    }
+
     //-----------------------------------------------------------------------
 
     public boolean add(final E object, final int count) {

Modified: 
commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/bag/SynchronizedBag.java
URL: 
http://svn.apache.org/viewvc/commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/bag/SynchronizedBag.java?rev=1651115&r1=1651114&r2=1651115&view=diff
==============================================================================
--- 
commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/bag/SynchronizedBag.java
 (original)
+++ 
commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/bag/SynchronizedBag.java
 Mon Jan 12 15:21:18 2015
@@ -82,6 +82,23 @@ public class SynchronizedBag<E> extends
         return (Bag<E>) decorated();
     }
 
+    @Override
+    public boolean equals(final Object object) {
+        if (object == this) {
+            return true;
+        }
+        synchronized (lock) {
+            return getBag().equals(object);
+        }
+    }
+
+    @Override
+    public int hashCode() {
+        synchronized (lock) {
+            return getBag().hashCode();
+        }
+    }
+
     //-----------------------------------------------------------------------
 
     public boolean add(final E object, final int count) {

Modified: 
commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/bag/TransformedBag.java
URL: 
http://svn.apache.org/viewvc/commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/bag/TransformedBag.java?rev=1651115&r1=1651114&r2=1651115&view=diff
==============================================================================
--- 
commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/bag/TransformedBag.java
 (original)
+++ 
commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/bag/TransformedBag.java
 Mon Jan 12 15:21:18 2015
@@ -18,10 +18,10 @@ package org.apache.commons.collections4.
 
 import java.util.Set;
 
-import org.apache.commons.collections4.set.TransformedSet;
 import org.apache.commons.collections4.Bag;
 import org.apache.commons.collections4.Transformer;
 import org.apache.commons.collections4.collection.TransformedCollection;
+import org.apache.commons.collections4.set.TransformedSet;
 
 /**
  * Decorates another {@link Bag} to transform objects that are added.
@@ -110,6 +110,16 @@ public class TransformedBag<E> extends T
         return (Bag<E>) decorated();
     }
 
+    @Override
+    public boolean equals(final Object object) {
+        return object == this || decorated().equals(object);
+    }
+
+    @Override
+    public int hashCode() {
+        return decorated().hashCode();
+    }
+
     //-----------------------------------------------------------------------
 
     public int getCount(final Object object) {

Modified: 
commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/bidimap/AbstractDualBidiMap.java
URL: 
http://svn.apache.org/viewvc/commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/bidimap/AbstractDualBidiMap.java?rev=1651115&r1=1651114&r2=1651115&view=diff
==============================================================================
--- 
commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/bidimap/AbstractDualBidiMap.java
 (original)
+++ 
commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/bidimap/AbstractDualBidiMap.java
 Mon Jan 12 15:21:18 2015
@@ -343,6 +343,16 @@ public abstract class AbstractDualBidiMa
         }
 
         @Override
+        public boolean equals(final Object object) {
+            return object == this || decorated().equals(object);
+        }
+
+        @Override
+        public int hashCode() {
+            return decorated().hashCode();
+        }
+
+        @Override
         public boolean removeAll(final Collection<?> coll) {
             if (parent.isEmpty() || coll.isEmpty()) {
                 return false;

Modified: 
commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/collection/AbstractCollectionDecorator.java
URL: 
http://svn.apache.org/viewvc/commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/collection/AbstractCollectionDecorator.java?rev=1651115&r1=1651114&r2=1651115&view=diff
==============================================================================
--- 
commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/collection/AbstractCollectionDecorator.java
 (original)
+++ 
commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/collection/AbstractCollectionDecorator.java
 Mon Jan 12 15:21:18 2015
@@ -34,6 +34,19 @@ import java.util.Iterator;
  * {@link #iterator()}. Instead it simply returns the value from the
  * wrapped collection. This may be undesirable, for example if you are trying
  * to write an unmodifiable implementation it might provide a loophole.
+ * <p>
+ * This implementation does not forward the hashCode and equals methods through
+ * to the backing object, but relies on Object's implementation. This is 
necessary
+ * to preserve the symmetry of equals. Custom definitions of equality are 
usually
+ * based on an interface, such as Set or List, so that the implementation of 
equals
+ * can cast the object being tested for equality to the custom interface.
+ * AbstractCollectionDecorator does not implement such custom interfaces 
directly;
+ * they are implemented only in subclasses. Therefore, forwarding equals would 
break
+ * symmetry, as the forwarding object might consider itself equal to the 
object being
+ * tested, but the reverse could not be true. This behavior is consistent with 
the
+ * JDK's collection wrappers, such as {@link 
java.util.Collections#unmodifiableCollection(Collection)}.
+ * Use an interface-specific subclass of AbstractCollectionDecorator, such as
+ * AbstractListDecorator, to preserve equality behavior, or override equals 
directly.
  *
  * @param <E> the type of the elements in the collection
  * @since 3.0
@@ -145,16 +158,6 @@ public abstract class AbstractCollection
     }
 
     @Override
-    public boolean equals(final Object object) {
-        return object == this || decorated().equals(object);
-    }
-
-    @Override
-    public int hashCode() {
-        return decorated().hashCode();
-    }
-
-    @Override
     public String toString() {
         return decorated().toString();
     }

Modified: 
commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/list/AbstractListDecorator.java
URL: 
http://svn.apache.org/viewvc/commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/list/AbstractListDecorator.java?rev=1651115&r1=1651114&r2=1651115&view=diff
==============================================================================
--- 
commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/list/AbstractListDecorator.java
 (original)
+++ 
commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/list/AbstractListDecorator.java
 Mon Jan 12 15:21:18 2015
@@ -65,6 +65,16 @@ public abstract class AbstractListDecora
         return (List<E>) super.decorated();
     }
 
+    @Override
+    public boolean equals(final Object object) {
+        return object == this || decorated().equals(object);
+    }
+
+    @Override
+    public int hashCode() {
+        return decorated().hashCode();
+    }
+
     //-----------------------------------------------------------------------
 
     public void add(final int index, final E object) {

Modified: 
commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/list/PredicatedList.java
URL: 
http://svn.apache.org/viewvc/commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/list/PredicatedList.java?rev=1651115&r1=1651114&r2=1651115&view=diff
==============================================================================
--- 
commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/list/PredicatedList.java
 (original)
+++ 
commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/list/PredicatedList.java
 Mon Jan 12 15:21:18 2015
@@ -94,6 +94,16 @@ public class PredicatedList<E> extends P
         return (List<E>) super.decorated();
     }
 
+    @Override
+    public boolean equals(final Object object) {
+        return object == this || decorated().equals(object);
+    }
+
+    @Override
+    public int hashCode() {
+        return decorated().hashCode();
+    }
+
     //-----------------------------------------------------------------------
 
     public E get(final int index) {

Modified: 
commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/list/TransformedList.java
URL: 
http://svn.apache.org/viewvc/commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/list/TransformedList.java?rev=1651115&r1=1651114&r2=1651115&view=diff
==============================================================================
--- 
commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/list/TransformedList.java
 (original)
+++ 
commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/list/TransformedList.java
 Mon Jan 12 15:21:18 2015
@@ -114,6 +114,16 @@ public class TransformedList<E> extends
         return (List<E>) decorated();
     }
 
+    @Override
+    public boolean equals(final Object object) {
+        return object == this || decorated().equals(object);
+    }
+
+    @Override
+    public int hashCode() {
+        return decorated().hashCode();
+    }
+
     //-----------------------------------------------------------------------
 
     public E get(final int index) {

Modified: 
commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/queue/AbstractQueueDecorator.java
URL: 
http://svn.apache.org/viewvc/commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/queue/AbstractQueueDecorator.java?rev=1651115&r1=1651114&r2=1651115&view=diff
==============================================================================
--- 
commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/queue/AbstractQueueDecorator.java
 (original)
+++ 
commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/queue/AbstractQueueDecorator.java
 Mon Jan 12 15:21:18 2015
@@ -24,6 +24,12 @@ import org.apache.commons.collections4.c
  * Decorates another {@link Queue} to provide additional behaviour.
  * <p>
  * Methods are forwarded directly to the decorated queue.
+ * <p>
+ * This implementation does not forward the hashCode and equals methods through
+ * to the backing object, but relies on Object's implementation. This is
+ * necessary as some Queue implementations, e.g. LinkedList, have custom a
+ * equals implementation for which symmetry can not be preserved.
+ * See class javadoc of AbstractCollectionDecorator for more information.
  *
  * @param <E> the type of the elements in the queue
  * @since 4.0

Modified: 
commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/set/AbstractSetDecorator.java
URL: 
http://svn.apache.org/viewvc/commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/set/AbstractSetDecorator.java?rev=1651115&r1=1651114&r2=1651115&view=diff
==============================================================================
--- 
commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/set/AbstractSetDecorator.java
 (original)
+++ 
commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/set/AbstractSetDecorator.java
 Mon Jan 12 15:21:18 2015
@@ -63,4 +63,14 @@ public abstract class AbstractSetDecorat
         return (Set<E>) super.decorated();
     }
 
+    @Override
+    public boolean equals(final Object object) {
+        return object == this || decorated().equals(object);
+    }
+
+    @Override
+    public int hashCode() {
+        return decorated().hashCode();
+    }
+
 }

Modified: 
commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/set/PredicatedSet.java
URL: 
http://svn.apache.org/viewvc/commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/set/PredicatedSet.java?rev=1651115&r1=1651114&r2=1651115&view=diff
==============================================================================
--- 
commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/set/PredicatedSet.java
 (original)
+++ 
commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/set/PredicatedSet.java
 Mon Jan 12 15:21:18 2015
@@ -86,4 +86,14 @@ public class PredicatedSet<E> extends Pr
         return (Set<E>) super.decorated();
     }
 
+    @Override
+    public boolean equals(final Object object) {
+        return object == this || decorated().equals(object);
+    }
+
+    @Override
+    public int hashCode() {
+        return decorated().hashCode();
+    }
+
 }

Modified: 
commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/set/TransformedSet.java
URL: 
http://svn.apache.org/viewvc/commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/set/TransformedSet.java?rev=1651115&r1=1651114&r2=1651115&view=diff
==============================================================================
--- 
commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/set/TransformedSet.java
 (original)
+++ 
commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/set/TransformedSet.java
 Mon Jan 12 15:21:18 2015
@@ -101,4 +101,14 @@ public class TransformedSet<E> extends T
         super(set, transformer);
     }
 
+    @Override
+    public boolean equals(final Object object) {
+        return object == this || decorated().equals(object);
+    }
+
+    @Override
+    public int hashCode() {
+        return decorated().hashCode();
+    }
+
 }

Modified: 
commons/proper/collections/trunk/src/test/java/org/apache/commons/collections4/multimap/AbstractMultiValuedMapTest.java
URL: 
http://svn.apache.org/viewvc/commons/proper/collections/trunk/src/test/java/org/apache/commons/collections4/multimap/AbstractMultiValuedMapTest.java?rev=1651115&r1=1651114&r2=1651115&view=diff
==============================================================================
--- 
commons/proper/collections/trunk/src/test/java/org/apache/commons/collections4/multimap/AbstractMultiValuedMapTest.java
 (original)
+++ 
commons/proper/collections/trunk/src/test/java/org/apache/commons/collections4/multimap/AbstractMultiValuedMapTest.java
 Mon Jan 12 15:21:18 2015
@@ -29,6 +29,7 @@ import java.util.Set;
 import org.apache.commons.collections4.AbstractObjectTest;
 import org.apache.commons.collections4.Bag;
 import org.apache.commons.collections4.BulkTest;
+import org.apache.commons.collections4.CollectionUtils;
 import org.apache.commons.collections4.MapIterator;
 import org.apache.commons.collections4.MultiValuedMap;
 import org.apache.commons.collections4.bag.AbstractBagTest;
@@ -754,7 +755,7 @@ public abstract class AbstractMultiValue
                 (MultiValuedMap<?, ?>) 
readExternalFormFromDisk(getCanonicalFullCollectionName(map));
         assertEquals("Map is the right size", map.size(), map2.size());
         for (final Object key : map.keySet()) {
-            assertEquals("Map had inequal elements", map.get(key), 
map2.get(key));
+            assertTrue("Map had inequal elements", 
CollectionUtils.isEqualCollection(map.get(key), map2.get(key)));
             if (isRemoveSupported()) {
                 map2.remove(key);
             }
@@ -1071,10 +1072,12 @@ public abstract class AbstractMultiValue
             return AbstractMultiValuedMapTest.this.makeObject().asMap();
         }
 
+        @Override
         public Map<K, Collection<V>> makeFullMap() {
             return AbstractMultiValuedMapTest.this.makeFullMap().asMap();
         }
 
+        @Override
         @SuppressWarnings("unchecked")
         public K[] getSampleKeys() {
             K[] samplekeys = AbstractMultiValuedMapTest.this.getSampleKeys();
@@ -1085,6 +1088,7 @@ public abstract class AbstractMultiValue
             return (K[]) finalKeys;
         }
 
+        @Override
         @SuppressWarnings("unchecked")
         public Collection<V>[] getSampleValues() {
             V[] sampleValues = 
AbstractMultiValuedMapTest.this.getSampleValues();
@@ -1095,6 +1099,7 @@ public abstract class AbstractMultiValue
             return colArr;
         }
 
+        @Override
         @SuppressWarnings("unchecked")
         public Collection<V>[] getNewSampleValues() {
             Object[] sampleValues = { "ein", "ek", "zwei", "duey", "drei", 
"teen" };


Reply via email to