Backport COLLECTIONS-266 to 3.2.2.
git-svn-id: https://svn.apache.org/repos/asf/commons/proper/collections/branches/COLLECTIONS_3_2_X@1713176 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
3afb3cb345
commit
fd1790522e
|
@ -26,6 +26,9 @@
|
||||||
<action issue="COLLECTIONS-335" dev="jochen" type="fix" due-to="sebb">
|
<action issue="COLLECTIONS-335" dev="jochen" type="fix" due-to="sebb">
|
||||||
Fixed cache assignment for "TreeBidiMap#entrySet".
|
Fixed cache assignment for "TreeBidiMap#entrySet".
|
||||||
</action>
|
</action>
|
||||||
|
<action issue="COLLECTIONS-266" dev="bayard" type="fix" due-to="Joerg Schaible">
|
||||||
|
"MultiKey" will now be correctly serialized/de-serialized.
|
||||||
|
</action>
|
||||||
<action issue="COLLECTIONS-249" dev="bayard" type="fix" due-to="Joe Kelly">
|
<action issue="COLLECTIONS-249" dev="bayard" type="fix" due-to="Joe Kelly">
|
||||||
"SetUniqueList.addAll(int, Collection)" now correctly add the collection at the
|
"SetUniqueList.addAll(int, Collection)" now correctly add the collection at the
|
||||||
provided index.
|
provided index.
|
||||||
|
@ -75,9 +78,6 @@
|
||||||
"CaseInsensitiveMap" will now convert input strings to lower-case in a
|
"CaseInsensitiveMap" will now convert input strings to lower-case in a
|
||||||
locale-independant manner.
|
locale-independant manner.
|
||||||
</action>
|
</action>
|
||||||
<action issue="COLLECTIONS-266" dev="bayard" type="fix" due-to="Joerg Schaible">
|
|
||||||
"MultiKey" will now be correctly serialized/de-serialized.
|
|
||||||
</action>
|
|
||||||
<action issue="COLLECTIONS-261" dev="bayard" type="fix" due-to="ori">
|
<action issue="COLLECTIONS-261" dev="bayard" type="fix" due-to="ori">
|
||||||
"Flat3Map#remove(Object)" will now return the correct value mapped to the removed key
|
"Flat3Map#remove(Object)" will now return the correct value mapped to the removed key
|
||||||
if the size of the map is less or equal 3.
|
if the size of the map is less or equal 3.
|
||||||
|
|
|
@ -54,7 +54,7 @@ public class MultiKey implements Serializable {
|
||||||
/** The individual keys */
|
/** The individual keys */
|
||||||
private final Object[] keys;
|
private final Object[] keys;
|
||||||
/** The cached hashCode */
|
/** The cached hashCode */
|
||||||
private final int hashCode;
|
private transient int hashCode;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor taking two keys.
|
* Constructor taking two keys.
|
||||||
|
@ -163,14 +163,8 @@ public class MultiKey implements Serializable {
|
||||||
} else {
|
} else {
|
||||||
this.keys = keys;
|
this.keys = keys;
|
||||||
}
|
}
|
||||||
|
|
||||||
int total = 0;
|
calculateHashCode(keys);
|
||||||
for (int i = 0; i < keys.length; i++) {
|
|
||||||
if (keys[i] != null) {
|
|
||||||
total ^= keys[i].hashCode();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
hashCode = total;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------
|
//-----------------------------------------------------------------------
|
||||||
|
@ -255,4 +249,30 @@ public class MultiKey implements Serializable {
|
||||||
return "MultiKey" + Arrays.asList(keys).toString();
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,15 @@
|
||||||
*/
|
*/
|
||||||
package org.apache.commons.collections.keyvalue;
|
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.Arrays;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import junit.framework.Assert;
|
import junit.framework.Assert;
|
||||||
import junit.framework.Test;
|
import junit.framework.Test;
|
||||||
|
@ -205,5 +213,50 @@ public class TestMultiKey extends TestCase {
|
||||||
Assert.assertTrue(mk1.equals("") == false);
|
Assert.assertTrue(mk1.equals("") == false);
|
||||||
Assert.assertTrue(mk1.equals(null) == false);
|
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));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue