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" };