Tree traversal with a TreeListIterator will not be affected anymore by
the removal of an element directly after a call to previous().
diff --git a/src/main/java/org/apache/commons/collections/CollectionUtils.java b/src/main/java/org/apache/commons/collections/CollectionUtils.java
index 4657eb927..ac97191e8 100644
--- a/src/main/java/org/apache/commons/collections/CollectionUtils.java
+++ b/src/main/java/org/apache/commons/collections/CollectionUtils.java
@@ -34,6 +34,7 @@ import org.apache.commons.collections.collection.SynchronizedCollection;
import org.apache.commons.collections.collection.TransformedCollection;
import org.apache.commons.collections.collection.UnmodifiableBoundedCollection;
import org.apache.commons.collections.collection.UnmodifiableCollection;
+import org.apache.commons.collections.functors.Equator;
import org.apache.commons.collections.functors.TruePredicate;
/**
@@ -522,6 +523,78 @@ public class CollectionUtils {
return true;
}
+ /**
+ * Returns true iff the given {@link Collection}s contain
+ * exactly the same elements with exactly the same cardinalities.
+ *
+ * That is, iff the cardinality of e in a is
+ * equal to the cardinality of e in b,
+ * for each element e in a or b.
+ *
+ * @param a the first collection, must not be null
+ * @param b the second collection, must not be null
+ * @param equator the Equator used for testing equality
+ * @return true
iff the collections contain the same elements with the same cardinalities.
+ * @throws IllegalArgumentException if the equator is null
+ * @since 4.0
+ */
+ @SuppressWarnings({ "unchecked", "rawtypes" }) // we don't know the types due to wildcards in the signature
+ public static boolean isEqualCollection(final Collection> a, final Collection> b, final Equator> equator) {
+ if (equator == null) {
+ throw new IllegalArgumentException("equator may not be null");
+ }
+
+ if(a.size() != b.size()) {
+ return false;
+ }
+
+ final Transformer transformer = new Transformer() {
+ public EquatorWrapper> transform(Object input) {
+ return new EquatorWrapper(equator, input);
+ }
+ };
+
+ return isEqualCollection(collect(a, transformer), collect(b, transformer));
+ }
+
+ /**
+ * Wraps another object and uses the provided Equator to implement
+ * {@link #equals(Object)} and {@link #hashCode()}.
+ *
+ * This class can be used to store objects into a Map.
+ *
+ * @param the element type
+ * @since 4.0
+ */
+ private static class EquatorWrapper {
+ private final Equator equator;
+ private final O object;
+
+ public EquatorWrapper(final Equator equator, final O object) {
+ this.equator = equator;
+ this.object = object;
+ }
+
+ public O getObject() {
+ return object;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof EquatorWrapper)) {
+ return false;
+ }
+ @SuppressWarnings("unchecked")
+ EquatorWrapper otherObj = (EquatorWrapper) obj;
+ return equator.equate(object, otherObj.getObject());
+ }
+
+ @Override
+ public int hashCode() {
+ return equator.hash(object);
+ }
+ }
+
/**
* Returns the number of occurrences of obj in coll.
*
diff --git a/src/test/java/org/apache/commons/collections/CollectionUtilsTest.java b/src/test/java/org/apache/commons/collections/CollectionUtilsTest.java
index 8dc7433c5..2d649e9ed 100644
--- a/src/test/java/org/apache/commons/collections/CollectionUtilsTest.java
+++ b/src/test/java/org/apache/commons/collections/CollectionUtilsTest.java
@@ -32,6 +32,8 @@ import org.apache.commons.collections.collection.PredicatedCollection;
import org.apache.commons.collections.collection.SynchronizedCollection;
import org.apache.commons.collections.collection.TransformedCollection;
import org.apache.commons.collections.collection.UnmodifiableCollection;
+import org.apache.commons.collections.functors.DefaultEquator;
+import org.apache.commons.collections.functors.Equator;
import org.junit.Before;
import org.junit.Test;
@@ -515,6 +517,36 @@ public class CollectionUtilsTest extends MockTestCase {
assertTrue(CollectionUtils.isEqualCollection(b, a));
}
+ @Test
+ public void testIsEqualCollectionEquator() {
+ Collection collB = CollectionUtils.collect(collectionB, TRANSFORM_TO_INTEGER);
+
+ // odd / even equator
+ final Equator e = new Equator() {
+ public boolean equate(Integer o1, Integer o2) {
+ if (o1.intValue() % 2 == 0 ^ o2.intValue() % 2 == 0) return false;
+ else return true;
+ }
+
+ public int hash(Integer o) {
+ return o.intValue() % 2 == 0 ? Integer.valueOf(0).hashCode() : Integer.valueOf(1).hashCode();
+ }
+ };
+
+ assertTrue(CollectionUtils.isEqualCollection(collectionA, collectionA, e));
+ assertTrue(CollectionUtils.isEqualCollection(collectionA, collB, e));
+ assertTrue(CollectionUtils.isEqualCollection(collB, collectionA, e));
+
+ final Equator defaultEquator = new DefaultEquator();
+ assertFalse(CollectionUtils.isEqualCollection(collectionA, collectionB, defaultEquator));
+ assertFalse(CollectionUtils.isEqualCollection(collectionA, collB, defaultEquator));
+ }
+
+ @Test(expected=IllegalArgumentException.class)
+ public void testIsEqualCollectionNullEquator() {
+ CollectionUtils.isEqualCollection(collectionA, collectionA, null);
+ }
+
@Test
public void testIsProperSubCollection() {
final Collection a = new ArrayList();