[COLLECTIONS-543] AbstractCollectionDecorator does not forward equals and hashCode anymore to the backing collection.
git-svn-id: https://svn.apache.org/repos/asf/commons/proper/collections/trunk@1651115 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
32155107dd
commit
30e5023265
|
@ -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>
|
||||
|
|
|
@ -63,6 +63,16 @@ public abstract class AbstractBagDecorator<E>
|
|||
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) {
|
||||
|
|
|
@ -87,6 +87,16 @@ public class PredicatedBag<E> extends PredicatedCollection<E> implements Bag<E>
|
|||
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) {
|
||||
|
|
|
@ -82,6 +82,23 @@ public class SynchronizedBag<E> extends SynchronizedCollection<E> implements Bag
|
|||
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) {
|
||||
|
|
|
@ -18,10 +18,10 @@ package org.apache.commons.collections4.bag;
|
|||
|
||||
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 TransformedCollection<E> implements Bag<E
|
|||
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) {
|
||||
|
|
|
@ -342,6 +342,16 @@ public abstract class AbstractDualBidiMap<K, V> implements BidiMap<K, V> {
|
|||
this.parent = parent;
|
||||
}
|
||||
|
||||
@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()) {
|
||||
|
|
|
@ -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
|
||||
|
@ -144,16 +157,6 @@ public abstract class AbstractCollectionDecorator<E>
|
|||
return decorated().retainAll(coll);
|
||||
}
|
||||
|
||||
@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();
|
||||
|
|
|
@ -65,6 +65,16 @@ public abstract class AbstractListDecorator<E> extends AbstractCollectionDecorat
|
|||
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) {
|
||||
|
|
|
@ -94,6 +94,16 @@ public class PredicatedList<E> extends PredicatedCollection<E> implements List<E
|
|||
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) {
|
||||
|
|
|
@ -114,6 +114,16 @@ public class TransformedList<E> extends TransformedCollection<E> implements List
|
|||
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) {
|
||||
|
|
|
@ -24,6 +24,12 @@ import org.apache.commons.collections4.collection.AbstractCollectionDecorator;
|
|||
* 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
|
||||
|
|
|
@ -63,4 +63,14 @@ public abstract class AbstractSetDecorator<E> extends AbstractCollectionDecorato
|
|||
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();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -86,4 +86,14 @@ public class PredicatedSet<E> extends PredicatedCollection<E> implements Set<E>
|
|||
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();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -101,4 +101,14 @@ public class TransformedSet<E> extends TransformedCollection<E> implements Set<E
|
|||
super(set, transformer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object object) {
|
||||
return object == this || decorated().equals(object);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return decorated().hashCode();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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 AbstractMultiValuedMapTest<K, V> extends AbstractObjectTes
|
|||
(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 AbstractMultiValuedMapTest<K, V> extends AbstractObjectTes
|
|||
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 AbstractMultiValuedMapTest<K, V> extends AbstractObjectTes
|
|||
return (K[]) finalKeys;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public Collection<V>[] getSampleValues() {
|
||||
V[] sampleValues = AbstractMultiValuedMapTest.this.getSampleValues();
|
||||
|
@ -1095,6 +1099,7 @@ public abstract class AbstractMultiValuedMapTest<K, V> extends AbstractObjectTes
|
|||
return colArr;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public Collection<V>[] getNewSampleValues() {
|
||||
Object[] sampleValues = { "ein", "ek", "zwei", "duey", "drei", "teen" };
|
||||
|
|
Loading…
Reference in New Issue