diff --git a/benchmarks/src/main/java/com/esotericsoftware/kryo/benchmarks/ArrayClassResolverBenchmark.java b/benchmarks/src/main/java/com/esotericsoftware/kryo/benchmarks/ArrayClassResolverBenchmark.java
new file mode 100644
index 000000000..1165bcec0
--- /dev/null
+++ b/benchmarks/src/main/java/com/esotericsoftware/kryo/benchmarks/ArrayClassResolverBenchmark.java
@@ -0,0 +1,154 @@
+/* Copyright (c) 2008-2022, Nathan Sweet
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided with the distribution.
+ * - Neither the name of Esoteric Software nor the names of its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+ * SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
+
+package com.esotericsoftware.kryo.benchmarks;
+
+import com.esotericsoftware.kryo.Kryo;
+import com.esotericsoftware.kryo.io.Input;
+import com.esotericsoftware.kryo.io.Output;
+import com.esotericsoftware.kryo.util.ArrayClassResolver;
+import org.openjdk.jmh.annotations.*;
+
+import java.util.*;
+
+import static com.esotericsoftware.kryo.benchmarks.FieldSerializerBenchmark.*;
+
+/**
+ * {@link ArrayClassResolver} is fast especially in {@link #deserializeCollection(DeserializingCollectionWithArrayClassResolverState)}}.
+ *
+ *
+ * Benchmark Mode Cnt Score Error Units
+ * ArrayClassResolverBenchmark.deserializeCollection thrpt 4125.996 ops/s +17%
+ * FieldSerializerBenchmark.deserializeCollection thrpt 3511.014 ops/s
+ *
+ * Comparing only readClass() by profiler.
+ * Total Time Invocations
+ * DefaultClassResolver.readClass() 19,872 ms 10,006,631
+ * ArrayClassResolver.readClass() 12,371 ms 10,029,051 60% faster
+ *
+ *
+ * @author lifeinwild1@gmail.com
+ */
+public class ArrayClassResolverBenchmark {
+ @Benchmark
+ public void field (FieldSerializerStateArray state) {
+ state.roundTrip();
+ }
+
+ @Benchmark
+ public void compatible (CompatibleStateArray state) {
+ state.roundTrip();
+ }
+
+ @Benchmark
+ public void tagged (TaggedStateArray state) {
+ state.roundTrip();
+ }
+
+ @Benchmark
+ public void version (VersionStateArray state) {
+ state.roundTrip();
+ }
+
+ @Benchmark
+ public void custom (CustomStateArray state) {
+ state.roundTrip();
+ }
+
+ @Benchmark
+ public void deserializeCollection(DeserializingCollectionWithArrayClassResolverState state) { state.roundTrip(); }
+
+ //
+
+ public static Kryo createKryoArray(){
+ return new Kryo(new ArrayClassResolver(), null);
+ }
+
+ static public class FieldSerializerStateArray extends FieldSerializerState {
+ @Override
+ public Kryo createKryo() {
+ return createKryoArray();
+ }
+ }
+
+ static public class CompatibleStateArray extends CompatibleState {
+ @Override
+ public Kryo createKryo() {
+ return createKryoArray();
+ }
+ }
+
+ static public class TaggedStateArray extends TaggedState {
+ @Override
+ public Kryo createKryo() {
+ return createKryoArray();
+ }
+ }
+
+ static public class VersionStateArray extends VersionState {
+ @Override
+ public Kryo createKryo() {
+ return createKryoArray();
+ }
+ }
+
+ static public class CustomStateArray extends CustomState {
+ @Override
+ public Kryo createKryo() {
+ return createKryoArray();
+ }
+ }
+
+ static public class DeserializingCollectionWithArrayClassResolverState extends DeserializingCollectionState {
+ @Override
+ protected Kryo createKryo() {
+ return createKryoArray();
+ }
+ }
+
+ @State(Scope.Thread)
+ static public abstract class DeserializingCollectionState{
+ final Kryo kryo = createKryo();
+ final Output output = new Output(1024 * 1024);
+ final Input input = new Input(output.getBuffer());
+ Object object;
+
+ abstract protected Kryo createKryo();
+
+ @Setup(Level.Trial)
+ public void setup () {
+ HashMap m = new HashMap<>();
+ for(long i=0;i<2000;i++)
+ m.put(i, "val");
+
+ object = m;
+
+ kryo.register(HashMap.class);
+
+ output.setPosition(0);
+ kryo.writeObject(output, object);
+ }
+
+ public void roundTrip() {
+ input.setPosition(0);
+ input.setLimit(output.position());
+ kryo.readObject(input, object.getClass());
+ }
+ }
+}
diff --git a/benchmarks/src/main/java/com/esotericsoftware/kryo/benchmarks/FieldSerializerBenchmark.java b/benchmarks/src/main/java/com/esotericsoftware/kryo/benchmarks/FieldSerializerBenchmark.java
index 491c98f6c..41ff0a50c 100644
--- a/benchmarks/src/main/java/com/esotericsoftware/kryo/benchmarks/FieldSerializerBenchmark.java
+++ b/benchmarks/src/main/java/com/esotericsoftware/kryo/benchmarks/FieldSerializerBenchmark.java
@@ -70,6 +70,9 @@ public void custom (CustomState state) {
state.roundTrip();
}
+ @Benchmark
+ public void deserializeCollection(DeserializingCollectionWithDefaultClassResolverState state) { state.roundTrip(); }
+
//
@State(Scope.Thread)
@@ -77,11 +80,15 @@ static public abstract class BenchmarkState {
@Param({"true", "false"}) public boolean references;
@Param() public ObjectType objectType;
- final Kryo kryo = new Kryo();
+ final Kryo kryo = createKryo();
final Output output = new Output(1024 * 512);
final Input input = new Input(output.getBuffer());
Object object;
+ public Kryo createKryo(){
+ return new Kryo();
+ }
+
@Setup(Level.Trial)
public void setup () {
switch (objectType) {
@@ -310,4 +317,11 @@ public void write (Kryo kryo, Output output, Image image) {
kryo.writeObjectOrNull(output, image.media, Media.class);
}
}
+
+ static public class DeserializingCollectionWithDefaultClassResolverState extends ArrayClassResolverBenchmark.DeserializingCollectionState {
+ @Override
+ protected Kryo createKryo() {
+ return new Kryo();
+ }
+ }
}
diff --git a/src/com/esotericsoftware/kryo/util/ArrayClassResolver.java b/src/com/esotericsoftware/kryo/util/ArrayClassResolver.java
new file mode 100644
index 000000000..57d0a2b40
--- /dev/null
+++ b/src/com/esotericsoftware/kryo/util/ArrayClassResolver.java
@@ -0,0 +1,218 @@
+/* Copyright (c) 2008-2022, Nathan Sweet
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided with the distribution.
+ * - Neither the name of Esoteric Software nor the names of its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+ * SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
+
+package com.esotericsoftware.kryo.util;
+
+import com.esotericsoftware.kryo.ClassResolver;
+import com.esotericsoftware.kryo.Kryo;
+import com.esotericsoftware.kryo.KryoException;
+import com.esotericsoftware.kryo.Registration;
+import com.esotericsoftware.kryo.io.Input;
+import com.esotericsoftware.kryo.io.Output;
+
+import static com.esotericsoftware.kryo.util.Util.*;
+import static com.esotericsoftware.minlog.Log.*;
+
+/** This is enhanced resolver from {@link DefaultClassResolver} for fast deserialization of collections.
+ *
+ * @author lifeinwild1@gmail.com
+ * @apiNote In terms of functionality, {@link ArrayClassResolver} is completely equivalent to {@link DefaultClassResolver}. So the
+ * output binary is equivalent to that of {@link DefaultClassResolver}.
+ * @implNote You can specify the mappings between class and ID by {@link Kryo#register(Class, int)}, But don't specify huge ID
+ * like 20000000 because this resolver uses array internally. This resolver internally reconstructs array of
+ * {@link IntToObjArray} when the mappings are added. Therefore, it is not suitable in terms of performance if the
+ * mappings are added frequently at peaktime of application. Use the {@link Pool}.
+ * @see Pool */
+public class ArrayClassResolver implements ClassResolver {
+ protected final IdentityMap classToRegistration = new IdentityMap<>();
+ private final IntToObjArray idToRegistrationTmp = new IntToObjArray<>(Registration.class);
+ protected Kryo kryo;
+ protected IdentityObjectIntMap classToNameId;
+ protected IntToObjArray nameIdToClass;
+ protected ObjectMap nameToClass;
+ protected int nextNameId;
+
+ private int memoizedClassId = -1;
+ private Registration memoizedClassIdValue;
+ private Class memoizedClass;
+ private Registration memoizedClassValue;
+
+ public void setKryo (Kryo kryo) {
+ this.kryo = kryo;
+ }
+
+ public Registration register (Registration registration) {
+ memoizedClassId = -1;
+ memoizedClass = null;
+ if (registration == null) throw new IllegalArgumentException("registration cannot be null.");
+ if (registration.getId() != DefaultClassResolver.NAME) {
+ if (TRACE) {
+ trace("kryo", "Register class ID " + registration.getId() + ": " + className(registration.getType()) + " ("
+ + registration.getSerializer().getClass().getName() + ")");
+ }
+ idToRegistrationTmp.put(registration.getId(), registration);
+ } else if (TRACE) {
+ trace("kryo", "Register class name: " + className(registration.getType()) + " ("
+ + registration.getSerializer().getClass().getName() + ")");
+ }
+ classToRegistration.put(registration.getType(), registration);
+ Class wrapperClass = getWrapperClass(registration.getType());
+ if (wrapperClass != registration.getType()) classToRegistration.put(wrapperClass, registration);
+ return registration;
+ }
+
+ public Registration registerImplicit (Class type) {
+ return register(new Registration(type, kryo.getDefaultSerializer(type), DefaultClassResolver.NAME));
+ }
+
+ public Registration getRegistration (Class type) {
+ if (type == memoizedClass) return memoizedClassValue;
+ Registration registration = classToRegistration.get(type);
+ if (registration != null) {
+ memoizedClass = type;
+ memoizedClassValue = registration;
+ }
+ return registration;
+ }
+
+ public Registration writeClass (Output output, Class type) {
+ if (type == null) {
+ if (TRACE || (DEBUG && kryo.getDepth() == 1)) log("Write", null, output.position());
+ output.writeByte(Kryo.NULL);
+ return null;
+ }
+ Registration registration = kryo.getRegistration(type);
+ if (registration.getId() == DefaultClassResolver.NAME)
+ writeName(output, type, registration);
+ else {
+ if (TRACE) trace("kryo", "Write class " + registration.getId() + ": " + className(type) + pos(output.position()));
+ output.writeVarInt(registration.getId() + 2, true);
+ }
+ return registration;
+ }
+
+ protected void writeName (Output output, Class type, Registration registration) {
+ output.writeByte(1); // NAME + 2
+ if (classToNameId != null) {
+ int nameId = classToNameId.get(type, -1);
+ if (nameId != -1) {
+ if (TRACE) trace("kryo", "Write class name reference " + nameId + ": " + className(type) + pos(output.position()));
+ output.writeVarInt(nameId, true);
+ return;
+ }
+ }
+ // Only write the class name the first time encountered in object graph.
+ if (TRACE) trace("kryo", "Write class name: " + className(type) + pos(output.position()));
+ int nameId = nextNameId++;
+ if (classToNameId == null) classToNameId = new IdentityObjectIntMap<>();
+ classToNameId.put(type, nameId);
+ output.writeVarInt(nameId, true);
+ if (registration.isTypeNameAscii())
+ output.writeAscii(type.getName());
+ else
+ output.writeString(type.getName());
+ }
+
+ protected Registration readName (Input input) {
+ int nameId = input.readVarInt(true);
+ if (nameIdToClass == null) nameIdToClass = new IntToObjArray<>(Class.class, nameId + 20);
+ Class type = nameIdToClass.get(nameId);
+ if (type == null) {
+ // Only read the class name the first time encountered in object graph.
+ String className = input.readString();
+ type = getTypeByName(className);
+ if (type == null) {
+ try {
+ type = Class.forName(className, false, kryo.getClassLoader());
+ } catch (ClassNotFoundException ex) {
+ // Fallback to Kryo's class loader.
+ try {
+ type = Class.forName(className, false, Kryo.class.getClassLoader());
+ } catch (ClassNotFoundException ex2) {
+ throw new KryoException("Unable to find class: " + className, ex);
+ }
+ }
+ if (nameToClass == null) nameToClass = new ObjectMap<>();
+ nameToClass.put(className, type);
+ }
+ nameIdToClass.put(nameId, type);
+ if (TRACE) trace("kryo", "Read class name: " + className + pos(input.position()));
+ } else {
+ if (TRACE) trace("kryo", "Read class name reference " + nameId + ": " + className(type) + pos(input.position()));
+ }
+ return kryo.getRegistration(type);
+ }
+
+ protected Class getTypeByName (final String className) {
+ return nameToClass != null ? nameToClass.get(className) : null;
+ }
+
+ public void reset () {
+ if (!kryo.isRegistrationRequired()) {
+ if (classToNameId != null) classToNameId.clear(2048);
+ if (nameIdToClass != null) nameIdToClass.clear();
+ nextNameId = 0;
+ }
+ }
+
+ @Override
+ public final Registration getRegistration (int classID) {
+ return idToRegistrationTmp.get(classID);
+ }
+
+ @Override
+ public Registration readClass (Input input) {
+ int classID = input.readVarInt(true);
+ switch (classID) {
+ case Kryo.NULL:
+ if (TRACE || (DEBUG && kryo.getDepth() == 1)) log("Read", null, input.position());
+ return null;
+ case DefaultClassResolver.NAME + 2: // Offset for NAME and NULL.
+ return readName(input);
+ }
+
+ if (classID == memoizedClassId) {
+ if (TRACE) trace("kryo",
+ "Read class " + (classID - 2) + ": " + className(memoizedClassIdValue.getType()) + pos(input.position()));
+ return memoizedClassIdValue;
+ }
+
+ int index = classID - 2;
+ Registration registration = getRegistration(index);
+ if (registration == null) throw new KryoException("Encountered unregistered class ID: " + (classID - 2));
+ if (TRACE) trace("kryo", "Read class " + (classID - 2) + ": " + className(registration.getType()) + pos(input.position()));
+
+ memoizedClassId = classID;
+ memoizedClassIdValue = registration;
+
+ return registration;
+ }
+
+ public Registration unregister (int classID) {
+ Registration registration = idToRegistrationTmp.remove(classID);
+ if (registration != null) {
+ classToRegistration.remove(registration.getType());
+ memoizedClassId = -1;
+ memoizedClass = null;
+ Class wrapperClass = getWrapperClass(registration.getType());
+ if (wrapperClass != registration.getType()) classToRegistration.remove(wrapperClass);
+ }
+ return registration;
+ }
+}
diff --git a/src/com/esotericsoftware/kryo/util/IntToObjArray.java b/src/com/esotericsoftware/kryo/util/IntToObjArray.java
new file mode 100644
index 000000000..284ce52aa
--- /dev/null
+++ b/src/com/esotericsoftware/kryo/util/IntToObjArray.java
@@ -0,0 +1,84 @@
+/* Copyright (c) 2008-2022, Nathan Sweet
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided with the distribution.
+ * - Neither the name of Esoteric Software nor the names of its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+ * SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
+
+package com.esotericsoftware.kryo.util;
+
+import java.lang.reflect.Array;
+
+/** LUT by array.
+ *
+ * @apiNote don't specify large int to key by {@link #put(int, Object)}.
+ * @author lifeinwild1@gmail.com */
+public final class IntToObjArray {
+ private final Class valueType;
+ private final int initialCapacity;
+ private final float expandRate;
+ private E[] array;
+
+ public final E get (int key) {
+ if (key >= array.length || key < 0) {
+ return null;
+ }
+ return array[key];
+ }
+
+ IntToObjArray (Class valueType, int initialCapacity, float expansionRate) {
+ if (expansionRate <= 1.0)
+ throw new IllegalArgumentException("expansionRate <= 1.0");
+ if (initialCapacity <= 0)
+ throw new IllegalArgumentException("initialCapacity <= 0");
+ this.valueType = valueType;
+ array = (E[])Array.newInstance(valueType, initialCapacity);
+ this.initialCapacity = initialCapacity;
+ this.expandRate = expansionRate;
+ }
+
+ IntToObjArray (Class valueType, int initialCapacity) {
+ this(valueType, initialCapacity, 1.1f);
+ }
+
+ IntToObjArray (Class valueType) {
+ this(valueType, 1000);
+ }
+
+ public void clear () {
+ array = (E[])Array.newInstance(valueType, initialCapacity);
+ }
+
+ public E remove (int classid) {
+ if (classid >= array.length)
+ return null;
+ E r = array[classid];
+ array[classid] = null;
+ return r;
+ }
+
+ public E put (int classid, E v) {
+ if (classid >= array.length && array.length < Integer.MAX_VALUE) {
+ int nextSize = (int)(classid * expandRate);
+ E[] next = (E[])Array.newInstance(valueType, nextSize);
+ System.arraycopy(array, 0, next, 0, array.length);
+ array = next;
+ }
+
+ E r = array[classid];
+ array[classid] = v;
+ return r;
+ }
+}
diff --git a/test/com/esotericsoftware/kryo/util/ArrayClassResolverTest.java b/test/com/esotericsoftware/kryo/util/ArrayClassResolverTest.java
new file mode 100644
index 000000000..e10da35ee
--- /dev/null
+++ b/test/com/esotericsoftware/kryo/util/ArrayClassResolverTest.java
@@ -0,0 +1,146 @@
+/* Copyright (c) 2008-2022, Nathan Sweet
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided with the distribution.
+ * - Neither the name of Esoteric Software nor the names of its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+ * SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
+
+package com.esotericsoftware.kryo.util;
+
+import com.esotericsoftware.kryo.Kryo;
+import com.esotericsoftware.kryo.KryoTestCase;
+import com.esotericsoftware.kryo.Registration;
+import com.esotericsoftware.kryo.Serializer;
+import com.esotericsoftware.kryo.io.Input;
+import com.esotericsoftware.kryo.io.Output;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+/**
+ * You can test {@link ArrayClassResolver} also by below method:
+ * temporarily modify {@link KryoTestCase#setUp()}, then run all test cases.
+ *
+ *
+ * @BeforeEach
+ * public void setUp () throws Exception {
+ * if (debug && WARN) warn("*** DEBUG TEST ***");
+ *
+ * kryo = new Kryo(new ArrayClassResolver(), null);
+ * }
+ *
+ *
+ * @author lifeinwild1@gmail.com
+ */
+public class ArrayClassResolverTest extends KryoTestCase {
+ @BeforeEach
+ public void setUp () throws Exception {
+ super.setUp();
+
+ ArrayClassResolver resolver = new ArrayClassResolver();
+ kryo = new Kryo(resolver, null);
+ kryo.register(ArrayList.class);
+ }
+
+ @Test
+ void testHugeID () {
+ ArrayClassResolver resolver = new ArrayClassResolver();
+
+ int id0 = 0;
+ Registration input0 = new Registration(TestModel0.class, new TestSerializer0(), id0);
+ resolver.register(input0);
+
+ int id1 = 1;
+ Registration input1 = new Registration(TestModel1.class, new TestSerializer1(), id1);
+ resolver.register(input1);
+
+ int id1000000 = 1000000;
+ Registration input1000000 = new Registration(TestModel1000000.class, new TestSerializer1000000(), id1000000);
+ resolver.register(input1000000);
+
+ Registration r0 = resolver.getRegistration(id0);
+ assertEquals(input0, r0);
+
+ Registration r1 = resolver.getRegistration(id1);
+ assertEquals(input1, r1);
+
+ Registration r1000000 = resolver.getRegistration(id1000000);
+ assertEquals(input1000000, r1000000);
+ }
+
+ private static class TestModel1{
+
+ }
+ private static class TestSerializer1 extends Serializer {
+
+ @Override
+ public void write(Kryo kryo, Output output, TestModel1 object) {
+
+ }
+
+ @Override
+ public TestModel1 read(Kryo kryo, Input input, Class extends TestModel1> type) {
+ return null;
+ }
+ }
+
+ private static class TestModel0{
+
+ }
+ private static class TestSerializer0 extends Serializer {
+
+ @Override
+ public void write(Kryo kryo, Output output, TestModel0 object) {
+
+ }
+
+ @Override
+ public TestModel0 read(Kryo kryo, Input input, Class extends TestModel0> type) {
+ return null;
+ }
+ }
+ private static class TestModel1000000{
+
+ }
+ private static class TestSerializer1000000 extends Serializer {
+
+ @Override
+ public void write(Kryo kryo, Output output, TestModel1000000 object) {
+
+ }
+
+ @Override
+ public TestModel1000000 read(Kryo kryo, Input input, Class extends TestModel1000000> type) {
+ return null;
+ }
+ }
+ @Test
+ void testArrayList () {
+ ArrayList test = new ArrayList();
+ test.add("one");
+ test.add("two");
+ test.add("three");
+
+ ArrayList copy = kryo.copy(test);
+ assertNotSame(test, copy);
+ assertEquals(test, copy);
+ }
+
+
+}