commons-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From bay...@apache.org
Subject svn commit: r661577 - in /commons/proper/collections/trunk/src: java/org/apache/commons/collections/keyvalue/MultiKey.java test/org/apache/commons/collections/keyvalue/TestMultiKey.java
Date Fri, 30 May 2008 06:23:45 GMT
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));		
+	}
 }



Mime
View raw message