Skip to content

Commit

Permalink
#940 Fix type resolution for generic arrays
Browse files Browse the repository at this point in the history
  • Loading branch information
theigl committed Apr 19, 2023
1 parent b2610a5 commit 0dea986
Show file tree
Hide file tree
Showing 4 changed files with 172 additions and 1 deletion.
5 changes: 4 additions & 1 deletion src/com/esotericsoftware/kryo/serializers/ReflectField.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import com.esotericsoftware.kryo.io.Output;
import com.esotericsoftware.kryo.serializers.FieldSerializer.CachedField;
import com.esotericsoftware.kryo.util.Generics.GenericType;
import com.esotericsoftware.kryo.util.Util;

import java.lang.reflect.Field;

Expand Down Expand Up @@ -151,7 +152,9 @@ public void read (Input input, Object object) {
Class resolveFieldClass () {
if (valueClass == null) {
Class fieldClass = genericType.resolve(fieldSerializer.kryo.getGenerics());
if (fieldClass != null && fieldSerializer.kryo.isFinal(fieldClass)) return fieldClass;
if (fieldClass != null && fieldSerializer.kryo.isFinal(fieldClass)) {
return field.getType().isArray() ? Util.getArrayType(fieldClass) : fieldClass;
}
}
return valueClass;
}
Expand Down
16 changes: 16 additions & 0 deletions src/com/esotericsoftware/kryo/util/Util.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import com.esotericsoftware.kryo.serializers.FieldSerializer;
import com.esotericsoftware.kryo.util.Generics.GenericType;

import java.lang.reflect.Array;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.Map;
Expand Down Expand Up @@ -110,6 +111,21 @@ public static Class getPrimitiveClass (Class type) {
return type;
}

/** Returns the array type for a given class */
public static Class getArrayType(Class type) {
if (type == String.class) return String[].class;
if (type == Integer.class) return Integer[].class;
if (type == Float.class) return Float[].class;
if (type == Boolean.class) return Boolean[].class;
if (type == Byte.class) return Byte[].class;
if (type == Long.class) return Long[].class;
if (type == Character.class) return Character[].class;
if (type == Double.class) return Double[].class;
if (type == Short.class) return Short[].class;
// See Class#arrayType() available from JDK 12
return Array.newInstance(type, 0).getClass();
}

public static boolean isWrapperClass (Class type) {
return type == Integer.class || type == Float.class || type == Boolean.class || type == Byte.class || type == Long.class
|| type == Character.class || type == Double.class || type == Short.class;
Expand Down
144 changes: 144 additions & 0 deletions test/com/esotericsoftware/kryo/serializers/GenericsTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,38 @@ void testFieldWithGenericArrayType() {
roundTrip(70, o);
}

// Test for https://github.com/EsotericSoftware/kryo/issues/940
@Test
void testFieldWithStringArrayType () {
StringArray array = new StringArray(new String[] {"1"});

kryo.setRegistrationRequired(false);

roundTrip(67, array);
}

// Test for https://github.com/EsotericSoftware/kryo/issues/940
@Test
void testFieldWithNumberArrayType () {
NumberArray<Integer> array = new NumberArray<>(new Integer[] {1});
NumberArrayHolder container = new NumberArrayHolder(array);

kryo.setRegistrationRequired(false);

roundTrip(137, container);
}

// Test for https://github.com/EsotericSoftware/kryo/issues/940
@Test
void testFieldWithObjectArrayType () {
ObjectArray<TestObject> array = new ObjectArray<>(new TestObject[] {new TestObject(1)});
ObjectArrayHolder container = new ObjectArrayHolder(array);

kryo.setRegistrationRequired(false);

roundTrip(265, container);
}

// Test for https://github.com/EsotericSoftware/kryo/issues/655
@Test
void testClassWithMultipleGenericTypes() {
Expand Down Expand Up @@ -565,4 +597,116 @@ interface C<T> {
}
}

public static class StringArray {

private String[] values;

public StringArray() {
}

public StringArray(String[] array) {
this.values = array;
}

public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
StringArray that = (StringArray) o;
return Arrays.equals(values, that.values);
}
}

public static class NumberArray<V extends Number> {

private V[] values;

public NumberArray() {
}

public NumberArray(V[] array) {
this.values = array;
}

public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
NumberArray<?> that = (NumberArray<?>) o;
return Arrays.equals(values, that.values);
}
}

public static class NumberArrayHolder {

private NumberArray<Integer> field;

public NumberArrayHolder() {
}

public NumberArrayHolder(NumberArray<Integer> array) {
this.field = array;
}

public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
NumberArrayHolder that = (NumberArrayHolder) o;
return Objects.equals(field, that.field);
}
}

public static class ObjectArray<V> {

private V[] values;

public ObjectArray() {
}

public ObjectArray(V[] array) {
this.values = array;
}

public boolean equals (Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ObjectArray<?> that = (ObjectArray<?>)o;
return Arrays.equals(values, that.values);
}
}

public static class ObjectArrayHolder {

private ObjectArray<TestObject> field;

public ObjectArrayHolder() {
}

public ObjectArrayHolder(ObjectArray<TestObject> array) {
this.field = array;
}

public boolean equals (Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ObjectArrayHolder that = (ObjectArrayHolder)o;
return Objects.equals(field, that.field);
}
}

public static class TestObject {
private int i;

public TestObject() {
}

public TestObject(int i) {
this.i = i;
}

public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
TestObject that = (TestObject) o;
return i == that.i;
}
}
}
8 changes: 8 additions & 0 deletions test/com/esotericsoftware/kryo/util/UtilTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,12 @@ void testIsAssignableTo() {
assertFalse(Util.isAssignableTo(String.class, long.class));
}

@Test
void testGetArrayType() {
assertEquals(int[].class, Util.getArrayType(int.class));
assertEquals(Integer[].class, Util.getArrayType(Integer.class));
assertEquals(String[].class, Util.getArrayType(String.class));
assertEquals(String[].class, Util.getArrayType(String.class));
assertEquals(Object[].class, Util.getArrayType(Object.class));
}
}

0 comments on commit 0dea986

Please sign in to comment.