Skip to content

Commit

Permalink
#847 Ensure that RecordSerializer can deal with subtypes
Browse files Browse the repository at this point in the history
  • Loading branch information
theigl committed Jul 29, 2021
1 parent 46dcc70 commit 20765bc
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 7 deletions.
28 changes: 24 additions & 4 deletions src/com/esotericsoftware/kryo/serializers/RecordSerializer.java
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@ public class RecordSerializer<T> extends ImmutableSerializer<T> {
GET_TYPE = getType;
}

private boolean fixedFieldTypes = false;

public RecordSerializer () {
}

Expand All @@ -83,10 +85,14 @@ public void write (Kryo kryo, Output output, T object) {
final String name = rc.name();
try {
if (TRACE) trace("kryo", "Write property: " + name + " (" + type.getName() + ")");
if (rc.type().isPrimitive()) {
if (type.isPrimitive()) {
kryo.writeObject(output, componentValue(object, rc));
} else {
kryo.writeObjectOrNull(output, componentValue(object, rc), type);
if (fixedFieldTypes || kryo.isFinal(type)) {
kryo.writeObjectOrNull(output, componentValue(object, rc), type);
} else {
kryo.writeClassAndObject(output, componentValue(object, rc));
}
}
} catch (KryoException ex) {
ex.addTrace(name + " (" + type.getName() + ")");
Expand All @@ -109,11 +115,19 @@ public T read (Kryo kryo, Input input, Class<? extends T> type) {
for (int i = 0; i < recordComponents.length; i++) {
final RecordComponent rc = recordComponents[i];
final String name = rc.name();
final Class<?> rcType = rc.type();
try {
if (TRACE) trace("kryo", "Read property: " + name + " (" + type.getName() + ")");
// Populate values in the order required by the canonical constructor
values[rc.index()] = rc.type().isPrimitive() ? kryo.readObject(input, rc.type())
: kryo.readObjectOrNull(input, rc.type());
if (rcType.isPrimitive()) {
values[rc.index()] = kryo.readObject(input, rcType);
} else {
if (fixedFieldTypes || kryo.isFinal(rcType)) {
values[rc.index()] = kryo.readObjectOrNull(input, rcType);
} else {
values[rc.index()] = kryo.readClassAndObject(input);
}
}
} catch (KryoException ex) {
ex.addTrace(name + " (" + type.getName() + ")");
throw ex;
Expand Down Expand Up @@ -214,4 +228,10 @@ private static <T> T invokeCanonicalConstructor (Class<T> recordType,
throw ex;
}
}

/** Tells the RecordSerializer that all field types are effectively final. This allows the serializer to be more efficient,
* since it knows field values will not be a subclass of their declared type. Default is false. */
public void setFixedFieldTypes (boolean fixedFieldTypes) {
this.fixedFieldTypes = fixedFieldTypes;
}
}
4 changes: 2 additions & 2 deletions test-jdk14/com/esotericsoftware/kryo/TestDataJava14.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,11 @@
* @author Chris Hegarty <chris.hegarty@oracle.com>
*/
public class TestDataJava14 extends SerializationCompatTestData.TestData {
public record Rec (byte b, short s, int i, long l, float f, double d, boolean bool, char c, String str, Number[] n) { };
public record Rec (byte b, short s, int i, long l, float f, double d, boolean bool, char c, String str, Integer[] n) { };

private Rec rec;

public TestDataJava14() {
rec = new Rec("b".getBytes()[0], (short)1, 2, 3L, 4.0f, 5.0d, true, 'c', "foo", new Number[]{1,2,3});
rec = new Rec("b".getBytes()[0], (short)1, 2, 3L, 4.0f, 5.0d, true, 'c', "foo", new Integer[]{1,2,3});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

package com.esotericsoftware.kryo.serializers;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.*;

import com.esotericsoftware.kryo.KryoException;
import com.esotericsoftware.kryo.KryoTestCase;
Expand Down Expand Up @@ -301,4 +301,22 @@ public void testRecordWithParametersReordered2() {

roundTrip(6, r2);
}

public static record RecordWithSuperType(Number n) {}

@Test
void testRecordWithSuperType() {
var rc = new RecordSerializer<RecordWithSuperType>();
rc.setFixedFieldTypes(false);
kryo.register(RecordWithSuperType.class, rc);

final var r = new RecordWithSuperType(1L);
final var output = new Output(32);
kryo.writeObject(output, r);
final var input = new Input(output.getBuffer(), 0, output.position());
final var r2 = kryo.readObject(input, RecordWithSuperType.class);

roundTrip(3, r2);
}

}

0 comments on commit 20765bc

Please sign in to comment.