Author: dlaha
Date: Sat Jul 12 21:10:23 2014
New Revision: 1610049

URL: http://svn.apache.org/r1610049
Log:
[COLLECTIONS-508] Updating equals and hashCode for ListValuedMap, SetValuedMap 
and MultiValuedMap

Modified:
    
commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/multimap/AbstractListValuedMap.java
    
commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/multimap/AbstractMultiValuedMap.java
    
commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/multimap/AbstractSetValuedMap.java
    
commons/proper/collections/trunk/src/test/java/org/apache/commons/collections4/multimap/MultiValuedHashMapTest.java

Modified: 
commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/multimap/AbstractListValuedMap.java
URL: 
http://svn.apache.org/viewvc/commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/multimap/AbstractListValuedMap.java?rev=1610049&r1=1610048&r2=1610049&view=diff
==============================================================================
--- 
commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/multimap/AbstractListValuedMap.java
 (original)
+++ 
commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/multimap/AbstractListValuedMap.java
 Sat Jul 12 21:10:23 2014
@@ -18,9 +18,12 @@ package org.apache.commons.collections4.
 
 import java.io.Serializable;
 import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
 import java.util.List;
 import java.util.ListIterator;
 import java.util.Map;
+import java.util.Map.Entry;
 
 import org.apache.commons.collections4.ListUtils;
 import org.apache.commons.collections4.ListValuedMap;
@@ -97,6 +100,49 @@ public abstract class AbstractListValued
         return ListUtils.emptyIfNull((List<V>) getMap().remove(key));
     }
 
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (obj instanceof ListValuedMap == false) {
+            return false;
+        }
+        ListValuedMap<?, ?> other = (ListValuedMap<?, ?>) obj;
+        if (other.size() != size()) {
+            return false;
+        }
+        Iterator<?> it = keySet().iterator();
+        while (it.hasNext()) {
+            Object key = it.next();
+            List<?> list = get(key);
+            List<?> otherList = other.get(key);
+            if (otherList == null) {
+                return false;
+            }
+            if (ListUtils.isEqualList(list, otherList) == false) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        int h = 0;
+        Iterator<Entry<K, Collection<V>>> it = getMap().entrySet().iterator();
+        while (it.hasNext()) {
+            Entry<K, Collection<V>> entry = it.next();
+            K key = entry.getKey();
+            List<V> valueList = (List<V>) entry.getValue();
+            h += (key == null ? 0 : key.hashCode()) ^ 
ListUtils.hashCodeForList(valueList);
+        }
+        return h;
+    }
+
     /**
      * Wrapped list to handle add and remove on the list returned by 
get(object)
      */
@@ -173,6 +219,34 @@ public abstract class AbstractListValued
             return list.subList(fromIndex, toIndex);
         }
 
+        @Override
+        public boolean equals(Object other) {
+            final List<V> list = (List<V>) getMapping();
+            if (list == null) {
+                return Collections.emptyList().equals(other);
+            }
+            if (other == null) {
+                return false;
+            }
+            if (!(other instanceof List)) {
+                return false;
+            }
+            List<?> otherList = (List<?>) other;
+            if (ListUtils.isEqualList(list, otherList) == false) {
+                return false;
+            }
+            return true;
+        }
+
+        @Override
+        public int hashCode() {
+            final List<V> list = (List<V>) getMapping();
+            if (list == null) {
+                return Collections.emptyList().hashCode();
+            }
+            return ListUtils.hashCodeForList(list);
+        }
+
     }
 
     /** Values ListItrerator */

Modified: 
commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/multimap/AbstractMultiValuedMap.java
URL: 
http://svn.apache.org/viewvc/commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/multimap/AbstractMultiValuedMap.java?rev=1610049&r1=1610048&r2=1610049&view=diff
==============================================================================
--- 
commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/multimap/AbstractMultiValuedMap.java
 (original)
+++ 
commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/multimap/AbstractMultiValuedMap.java
 Sat Jul 12 21:10:23 2014
@@ -396,7 +396,6 @@ public class AbstractMultiValuedMap<K, V
         return new MultiValuedMapIterator();
     }
 
-    @SuppressWarnings("rawtypes")
     @Override
     public boolean equals(Object obj) {
         if (this == obj) {
@@ -412,7 +411,7 @@ public class AbstractMultiValuedMap<K, V
         if (other.size() != size()) {
             return false;
         }
-        Iterator it = keySet().iterator();
+        Iterator<?> it = keySet().iterator();
         while (it.hasNext()) {
             Object key = it.next();
             Collection<?> col = get(key);
@@ -420,21 +419,34 @@ public class AbstractMultiValuedMap<K, V
             if (otherCol == null) {
                 return false;
             }
-            if (col.size() != otherCol.size()) {
+            if (CollectionUtils.isEqualCollection(col, otherCol) == false) {
                 return false;
             }
-            for (Object value : col) {
-                if (!otherCol.contains(value)) {
-                    return false;
-                }
-            }
         }
         return true;
     }
 
     @Override
     public int hashCode() {
-        return getMap().hashCode();
+        int h = 0;
+        Iterator<Entry<K, Collection<V>>> it = getMap().entrySet().iterator();
+        while (it.hasNext()) {
+            Entry<K, Collection<V>> entry = it.next();
+            K key = entry.getKey();
+            Collection<V> valueCol = entry.getValue();
+            int vh = 0;
+            if (valueCol != null) {
+                Iterator<V> colIt = valueCol.iterator();
+                while (colIt.hasNext()) {
+                    V val = colIt.next();
+                    if (val != null) {
+                        vh += val.hashCode();
+                    }
+                }
+            }
+            h += (key == null ? 0 : key.hashCode()) ^ vh;
+        }
+        return h;
     }
 
     @Override
@@ -588,7 +600,6 @@ public class AbstractMultiValuedMap<K, V
             return col.toArray(a);
         }
 
-        @SuppressWarnings("rawtypes")
         @Override
         public boolean equals(Object other) {
             final Collection<V> col = getMapping();
@@ -601,15 +612,10 @@ public class AbstractMultiValuedMap<K, V
             if(!(other instanceof Collection)){
                 return false;
             }
-            Collection otherCol = (Collection) other;
-            if (col.size() != otherCol.size()) {
+            Collection<?> otherCol = (Collection<?>) other;
+            if (CollectionUtils.isEqualCollection(col, otherCol) == false) {
                 return false;
             }
-            for (Object value : col) {
-                if (!otherCol.contains(value)) {
-                    return false;
-                }
-            }
             return true;
         }
 
@@ -619,7 +625,15 @@ public class AbstractMultiValuedMap<K, V
             if (col == null) {
                 return CollectionUtils.EMPTY_COLLECTION.hashCode();
             }
-            return col.hashCode();
+            int h = 0;
+            Iterator<V> it = col.iterator();
+            while (it.hasNext()) {
+                V val = it.next();
+                if (val != null) {
+                    h += val.hashCode();
+                }
+            }
+            return h;
         }
 
         @Override

Modified: 
commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/multimap/AbstractSetValuedMap.java
URL: 
http://svn.apache.org/viewvc/commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/multimap/AbstractSetValuedMap.java?rev=1610049&r1=1610048&r2=1610049&view=diff
==============================================================================
--- 
commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/multimap/AbstractSetValuedMap.java
 (original)
+++ 
commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/multimap/AbstractSetValuedMap.java
 Sat Jul 12 21:10:23 2014
@@ -16,8 +16,12 @@
  */
 package org.apache.commons.collections4.multimap;
 
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
 import java.util.Map;
 import java.util.Set;
+import java.util.Map.Entry;
 
 import org.apache.commons.collections4.SetUtils;
 import org.apache.commons.collections4.SetValuedMap;
@@ -93,6 +97,49 @@ public abstract class AbstractSetValuedM
         return SetUtils.emptyIfNull((Set<V>) getMap().remove(key));
     }
 
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (obj instanceof SetValuedMap == false) {
+            return false;
+        }
+        SetValuedMap<?, ?> other = (SetValuedMap<?, ?>) obj;
+        if (other.size() != size()) {
+            return false;
+        }
+        Iterator<?> it = keySet().iterator();
+        while (it.hasNext()) {
+            Object key = it.next();
+            Set<?> set = get(key);
+            Set<?> otherSet = other.get(key);
+            if (otherSet == null) {
+                return false;
+            }
+            if (SetUtils.isEqualSet(set, otherSet) == false) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        int h = 0;
+        Iterator<Entry<K, Collection<V>>> it = getMap().entrySet().iterator();
+        while (it.hasNext()) {
+            Entry<K, Collection<V>> entry = it.next();
+            K key = entry.getKey();
+            Set<V> valueSet = (Set<V>) entry.getValue();
+            h += (key == null ? 0 : key.hashCode()) ^ 
SetUtils.hashCodeForSet(valueSet);
+        }
+        return h;
+    }
+
     /**
      * Wrapped set to handle add and remove on the collection returned by
      * get(object)
@@ -103,6 +150,34 @@ public abstract class AbstractSetValuedM
             super(key);
         }
 
+        @Override
+        public boolean equals(Object other) {
+            final Set<V> set = (Set<V>) getMapping();
+            if (set == null) {
+                return Collections.emptySet().equals(other);
+            }
+            if (other == null) {
+                return false;
+            }
+            if (!(other instanceof Set)) {
+                return false;
+            }
+            Set<?> otherSet = (Set<?>) other;
+            if (SetUtils.isEqualSet(set, otherSet) == false) {
+                return false;
+            }
+            return true;
+        }
+
+        @Override
+        public int hashCode() {
+            final Set<V> set = (Set<V>) getMapping();
+            if (set == null) {
+                return Collections.emptySet().hashCode();
+            }
+            return SetUtils.hashCodeForSet(set);
+        }
+
     }
 
 }

Modified: 
commons/proper/collections/trunk/src/test/java/org/apache/commons/collections4/multimap/MultiValuedHashMapTest.java
URL: 
http://svn.apache.org/viewvc/commons/proper/collections/trunk/src/test/java/org/apache/commons/collections4/multimap/MultiValuedHashMapTest.java?rev=1610049&r1=1610048&r2=1610049&view=diff
==============================================================================
--- 
commons/proper/collections/trunk/src/test/java/org/apache/commons/collections4/multimap/MultiValuedHashMapTest.java
 (original)
+++ 
commons/proper/collections/trunk/src/test/java/org/apache/commons/collections4/multimap/MultiValuedHashMapTest.java
 Sat Jul 12 21:10:23 2014
@@ -163,6 +163,64 @@ public class MultiValuedHashMapTest<K, V
         assertEquals(2, listMap.get("B").size());
     }
 
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    public void testEqualsHashCodeContract() {
+        MultiValuedMap map1 = new MultiValuedHashMap();
+        MultiValuedMap map2 = new MultiValuedHashMap();
+
+        map1.put("a", "a1");
+        map1.put("a", "a2");
+        map2.put("a", "a2");
+        map2.put("a", "a1");
+        assertEquals(map1, map2);
+        assertEquals(map1.hashCode(), map2.hashCode());
+
+        map2.put("a", "a2");
+        assertNotSame(map1, map2);
+        assertNotSame(map1.hashCode(), map2.hashCode());
+    }
+
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    public void testListValuedMapEqualsHashCodeContract() {
+        ListValuedMap map1 = MultiValuedHashMap.listValuedHashMap();
+        ListValuedMap map2 = MultiValuedHashMap.listValuedHashMap();
+
+        map1.put("a", "a1");
+        map1.put("a", "a2");
+        map2.put("a", "a1");
+        map2.put("a", "a2");
+        assertEquals(map1, map2);
+        assertEquals(map1.hashCode(), map2.hashCode());
+
+        map1.put("b", "b1");
+        map1.put("b", "b2");
+        map2.put("b", "b2");
+        map2.put("b", "b1");
+        assertNotSame(map1, map2);
+        assertNotSame(map1.hashCode(), map2.hashCode());
+    }
+
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    public void testSetValuedMapEqualsHashCodeContract() {
+        SetValuedMap map1 = MultiValuedHashMap.setValuedHashMap();
+        SetValuedMap map2 = MultiValuedHashMap.setValuedHashMap();
+
+        map1.put("a", "a1");
+        map1.put("a", "a2");
+        map2.put("a", "a2");
+        map2.put("a", "a1");
+        assertEquals(map1, map2);
+        assertEquals(map1.hashCode(), map2.hashCode());
+
+        map2.put("a", "a2");
+        assertEquals(map1, map2);
+        assertEquals(map1.hashCode(), map2.hashCode());
+
+        map2.put("a", "a3");
+        assertNotSame(map1, map2);
+        assertNotSame(map1.hashCode(), map2.hashCode());
+    }
+
 //    public void testCreate() throws Exception {
 //        writeExternalFormToDisk((java.io.Serializable) makeObject(),
 //                
"src/test/resources/data/test/MultiValuedHashMap.emptyCollection.version4.1.obj");


Reply via email to