/*
* Copyright ( c ) 2014 , 2021 , Oracle and / or its affiliates . All rights reserved .
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER .
*
* This code is free software ; you can redistribute it and / or modify it
* under the terms of the GNU General Public License version 2 only , as
* published by the Free Software Foundation .
*
* This code is distributed in the hope that it will be useful , but WITHOUT
* ANY WARRANTY ; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE . See the GNU General Public License
* version 2 for more details ( a copy is included in the LICENSE file that
* accompanied this code ) .
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work ; if not , write to the Free Software Foundation ,
* Inc . , 51 Franklin St , Fifth Floor , Boston , MA 02110 - 1301 USA .
*
* Please contact Oracle , 500 Oracle Parkway , Redwood Shores , CA 94065 USA
* or visit www . oracle . com if you need additional information or have any
* questions .
*/
import java.io.*;
import java.lang.reflect.Field;
import java.util.Hashtable;
/**
* @ test
* @ bug 8068427
* @ summary Hashtable deserialization reconstitutes table with wrong capacity
* @ modules java . base / java . util : open
*/
public class DeserializedLength {
static boolean testDeserializedLength(int elements, float loadFactor) throws Exception {
// construct Hashtable with minimal initial capacity and given loadFactor
Hashtable<Integer, Integer> ht1 = new Hashtable<>(1 , loadFactor);
// add given number of unique elements
for (int i = 0 ; i < elements; i++) {
ht1.put(i, i);
}
// serialize and deserialize into a deep clone
Hashtable<Integer, Integer> ht2 = serialClone(ht1);
// compare lengths of internal tables
Object[] table1 = (Object[]) hashtableTableField.get(ht1);
Object[] table2 = (Object[]) hashtableTableField.get(ht2);
assert table1 != null ;
assert table2 != null ;
int minLength = (int ) (ht1.size() / loadFactor) + 1 ;
int maxLength = minLength * 2 ;
boolean ok = (table2.length >= minLength && table2.length <= maxLength);
System.out.printf(
"%7d %5.2f %7d %7d %7d...%7d %s\n" ,
ht1.size(), loadFactor,
table1.length, table2.length,
minLength, maxLength,
(ok ? "OK" : "NOT-OK" )
);
return ok;
}
static <T> T serialClone(T o) throws IOException, ClassNotFoundException {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try (ObjectOutputStream oos = new ObjectOutputStream(bos)) {
oos.writeObject(o);
}
@SuppressWarnings("unchecked" )
T clone = (T) new ObjectInputStream(
new ByteArrayInputStream(bos.toByteArray())).readObject();
return clone;
}
private static final Field hashtableTableField;
static {
try {
hashtableTableField = Hashtable.class .getDeclaredField("table" );
hashtableTableField.setAccessible(true );
} catch (NoSuchFieldException e) {
throw new Error(e);
}
}
public static void main(String[] args) throws Exception {
boolean ok = true ;
System.out.printf("Results:\n" +
" ser. deser.\n" +
" size load lentgh length valid range ok?\n" +
"------- ----- ------- ------- ----------------- ------\n"
);
for (int elements : new int []{10 , 50 , 500 , 5000 }) {
for (float loadFactor : new float []{0 .25 f, 0 .5 f, 0 .75 f, 1 .0 f, 2 .5 f}) {
ok &= testDeserializedLength(elements, loadFactor);
}
}
if (!ok) {
throw new AssertionError("Test failed." );
}
}
}
Messung V0.5 in Prozent C=95 H=88 G=91
¤ Dauer der Verarbeitung: 0.4 Sekunden
¤
*© Formatika GbR, Deutschland