[COLLECTIONS-599] HashEntry array object naming data initialized with

double the size during deserialization.
This commit is contained in:
Gary Gregory 2018-02-01 11:50:15 -07:00
parent 1e6435ec10
commit 4a9bcd0f52
3 changed files with 44 additions and 2 deletions

View File

@ -20,7 +20,10 @@
<title>Commons Collections Changes</title>
</properties>
<body>
<release version="4.2" date="YYYY-MM-DD" description="Update from Java 6 to Java 7 and small changes.">
<release version="4.2" date="2018-MM-DD" description="Update from Java 6 to Java 7, bug fixes, and small changes.">
<action issue="COLLECTIONS-599" dev="ggregory" type="fix" due-to="Tejas Patel, Saleem Akbar, Gary Gregory">
HashEntry array object naming data initialized with double the size during deserialization.
</action>
<action issue="COLLECTIONS-662" dev="chtompki" type="fix" due-to="Vamsi Kavuri">
Unit tests MapUtilsTest and ListIteratorWrapperTest no longer fail on Java 9.
</action>

View File

@ -1045,6 +1045,15 @@ public abstract class AbstractReferenceMap<K, V> extends AbstractHashedMap<K, V>
final int capacity = in.readInt();
init();
data = new HashEntry[capacity];
// COLLECTIONS-599: Calculate threshold before populating, otherwise it will be 0
// when it hits AbstractHashedMap.checkCapacity() and so will unnecessarily
// double up the size of the "data" array during population.
//
// NB: AbstractHashedMap.doReadObject() DOES calculate the threshold before populating.
//
threshold = calculateThreshold(data.length, loadFactor);
while (true) {
final K key = (K) in.readObject();
if (key == null) {
@ -1053,7 +1062,6 @@ public abstract class AbstractReferenceMap<K, V> extends AbstractHashedMap<K, V>
final V value = (V) in.readObject();
put(key, value);
}
threshold = calculateThreshold(data.length, loadFactor);
// do not call super.doReadObject() as code there doesn't work for reference map
}

View File

@ -16,6 +16,12 @@
*/
package org.apache.commons.collections4.map;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.ref.WeakReference;
import java.util.Map;
@ -249,6 +255,31 @@ public class ReferenceMapTest<K, V> extends AbstractIterableMapTest<K, V> {
}
}
/**
* Test whether after serialization the "data" HashEntry array is the same size as the original.<p>
*
* See <a href="https://issues.apache.org/jira/browse/COLLECTIONS-599">COLLECTIONS-599: HashEntry array object naming data initialized with double the size during deserialization</a>
*/
public void testDataSizeAfterSerialization() throws IOException, ClassNotFoundException {
ReferenceMap<String,String> serialiseMap = new ReferenceMap<>(ReferenceStrength.WEAK, ReferenceStrength.WEAK, true);
serialiseMap.put("KEY", "VALUE");
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try (ObjectOutputStream out = new ObjectOutputStream(baos)) {
out.writeObject(serialiseMap);
}
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
try (ObjectInputStream in = new ObjectInputStream(bais)) {
@SuppressWarnings("unchecked")
ReferenceMap<String,String> deserialisedMap = (ReferenceMap<String,String>) in.readObject();
assertEquals(1, deserialisedMap.size());
assertEquals(serialiseMap.data.length, deserialisedMap.data.length);
}
}
@SuppressWarnings("unused")
private static void gc() {
try {