Author: bayard
Date: Thu May 29 23:23:45 2008
New Revision: 661577

URL: http://svn.apache.org/viewvc?rev=661577&view=rev
Log:
Applying Joerg's final patch from COLLECTIONS-266, including the unit test that 
shows the problem and fixes the problem by making the hashcode transient, and 
moving the hashcode implementation such that it can be called from the 
deserialization as well as the hashcode method

Modified:
    
commons/proper/collections/trunk/src/java/org/apache/commons/collections/keyvalue/MultiKey.java
    
commons/proper/collections/trunk/src/test/org/apache/commons/collections/keyvalue/TestMultiKey.java

Modified: 
commons/proper/collections/trunk/src/java/org/apache/commons/collections/keyvalue/MultiKey.java
URL: 
http://svn.apache.org/viewvc/commons/proper/collections/trunk/src/java/org/apache/commons/collections/keyvalue/MultiKey.java?rev=661577&r1=661576&r2=661577&view=diff
==============================================================================
--- 
commons/proper/collections/trunk/src/java/org/apache/commons/collections/keyvalue/MultiKey.java
 (original)
+++ 
commons/proper/collections/trunk/src/java/org/apache/commons/collections/keyvalue/MultiKey.java
 Thu May 29 23:23:45 2008
@@ -16,6 +16,8 @@
  */
 package org.apache.commons.collections.keyvalue;
 
+import java.io.IOException;
+import java.io.ObjectInputStream;
 import java.io.Serializable;
 import java.util.Arrays;
 
@@ -54,7 +56,7 @@
     /** The individual keys */
     private final Object[] keys;
     /** The cached hashCode */
-    private final int hashCode;
+    private transient int hashCode;
     
     /**
      * Constructor taking two keys.
@@ -164,13 +166,7 @@
             this.keys = keys;
         }
         
-        int total = 0;
-        for (int i = 0; i < keys.length; i++) {
-            if (keys[i] != null) {
-                total ^= keys[i].hashCode();
-            }
-        }
-        hashCode = total;
+        calculateHashCode(keys);
     }
     
     //-----------------------------------------------------------------------
@@ -255,4 +251,29 @@
         return "MultiKey" + Arrays.asList(keys).toString();
     }
 
+       /**
+        * Calculate the hash code of the instance using the provided keys.
+        * @param keys
+        */
+       private void calculateHashCode(Object[] keys)
+       {
+               int total = 0;
+        for (int i = 0; i < keys.length; i++) {
+            if (keys[i] != null) {
+                total ^= keys[i].hashCode();
+            }
+        }
+        hashCode = total;
+       }
+       
+       /**
+        * Recalculate the hash code after deserialization. The hash code of 
some
+        * keys might have change (hash codes based on the system hash code are
+        * only stable for the same process). 
+        * @return the instance with recalculated hash code
+        */
+       private Object readResolve() {
+               calculateHashCode(keys);
+               return this;
+       }
 }

Modified: 
commons/proper/collections/trunk/src/test/org/apache/commons/collections/keyvalue/TestMultiKey.java
URL: 
http://svn.apache.org/viewvc/commons/proper/collections/trunk/src/test/org/apache/commons/collections/keyvalue/TestMultiKey.java?rev=661577&r1=661576&r2=661577&view=diff
==============================================================================
--- 
commons/proper/collections/trunk/src/test/org/apache/commons/collections/keyvalue/TestMultiKey.java
 (original)
+++ 
commons/proper/collections/trunk/src/test/org/apache/commons/collections/keyvalue/TestMultiKey.java
 Thu May 29 23:23:45 2008
@@ -16,7 +16,15 @@
  */
 package org.apache.commons.collections.keyvalue;
 
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
 import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
 
 import junit.framework.Assert;
 import junit.framework.Test;
@@ -206,4 +214,58 @@
         Assert.assertTrue(mk1.equals(null) == false);
     }
     
+    static class SystemHashCodeSimulatingKey implements Serializable {
+       
+               private static final long serialVersionUID = 1L;
+               private final String name;
+       private int hashCode = 1;
+
+               public SystemHashCodeSimulatingKey(String name)
+               {
+                       this.name = name;
+               }
+
+               public boolean equals(Object obj)
+               {
+                       return obj instanceof SystemHashCodeSimulatingKey 
+                               && 
name.equals(((SystemHashCodeSimulatingKey)obj).name);
+               }
+
+               public int hashCode()
+               {
+                       return hashCode;
+               }
+
+               private Object readResolve() {
+                       hashCode=2; // simulate different hashCode after 
deserialization in another process
+                       return this;
+               }
+    }
+    
+    public void testEqualsAfterSerialization() throws IOException, 
ClassNotFoundException
+       {
+        SystemHashCodeSimulatingKey sysKey = new 
SystemHashCodeSimulatingKey("test");
+               MultiKey mk = new MultiKey(ONE, sysKey);
+        Map map = new HashMap();
+        map.put(mk, TWO);
+
+        // serialize
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream(baos);
+        out.writeObject(sysKey);
+        out.writeObject(map);
+        out.close();
+
+        // deserialize
+        ByteArrayInputStream bais = new 
ByteArrayInputStream(baos.toByteArray());
+        ObjectInputStream in = new ObjectInputStream(bais);
+        sysKey = (SystemHashCodeSimulatingKey)in.readObject(); // simulate 
deserialization in another process
+        Map map2 = (Map) in.readObject();
+        in.close();
+
+        assertEquals(2, sysKey.hashCode()); // different hashCode now
+
+        MultiKey mk2 = new MultiKey(ONE, sysKey);
+        assertEquals(TWO, map2.get(mk2));              
+       }
 }


Reply via email to