Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add an exception for extendedFieldName #763

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -32,6 +32,9 @@
import com.esotericsoftware.kryo.util.ObjectMap;
import com.esotericsoftware.kryo.util.Util;

import java.lang.reflect.Field;
import java.util.HashSet;

/** Serializes objects using direct field assignment, providing both forward and backward compatibility. This means fields can be
* added or removed without invalidating previously serialized bytes. Renaming or changing the type of a field is not supported.
* Like {@link FieldSerializer}, it can serialize most classes without needing annotations.
Expand All @@ -58,6 +61,24 @@ public CompatibleFieldSerializer (Kryo kryo, Class type, CompatibleFieldSerializ
this.config = config;
}

@Override
protected void initializeCachedFields() {
if (config != null && !config.extendedFieldNames) {
final HashSet hashSet = new HashSet();
CachedField[] fields = cachedFields.fields;
for (int i = 0, n = fields.length; i < n; i++) {
final Field field = fields[i].field;
if (!hashSet.add(field.getName())) {
if (WARN)
warn("Detected duplicate field " + field.getName() + " in class hierarchy "
+ field.getDeclaringClass()
+ ". Consider enabling FieldSerializerConfig.extendedFieldNames");
break;
}
}
}
}

@Override
public void write (Kryo kryo, Output output, T object) {
int pop = pushTypeVariables();
Expand Down Expand Up @@ -289,6 +310,12 @@ public boolean getChunkedEncoding () {
return chunked;
}

@Override
public void setExtendedFieldNames(boolean extendedFieldNames) {
this.extendedFieldNames = extendedFieldNames;
if (TRACE) trace("kryo", "CompatibleFieldSerializerConfig extendedFieldNames: " + extendedFieldNames);
}

/** The maximum size of each chunk for chunked encoding. Default is 1024. */
public void setChunkSize (int chunkSize) {
this.chunkSize = chunkSize;
Expand Down
Expand Up @@ -125,7 +125,7 @@ public void write (Kryo kryo, Object object) {
output.flush();
}

class LoggerStub extends Logger {
public static class LoggerStub extends Logger {
public List<Integer> levels = new ArrayList();
public List<String> messages = new ArrayList();

Expand Down
Expand Up @@ -33,7 +33,10 @@
import java.util.List;
import java.util.Objects;

import com.esotericsoftware.kryo.WarnUnregisteredClassesTest;
import com.esotericsoftware.minlog.Log;
import org.apache.commons.lang.builder.EqualsBuilder;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
Expand All @@ -44,6 +47,16 @@ public class CompatibleFieldSerializerTest extends KryoTestCase {
supportsCopy = true;
}

WarnUnregisteredClassesTest.LoggerStub log;

@Before
public void setUp() throws Exception {
log = new WarnUnregisteredClassesTest.LoggerStub();
Log.setLogger(log);
Log.INFO();
kryo = new Kryo();
}

@Rule public ExpectedException exceptionRule = ExpectedException.none();

@Test
Expand Down Expand Up @@ -684,6 +697,47 @@ public int hashCode () {
}
}

@Test
public void testLogWarningOnDuplicateFieldInClassHierarchy() {
kryo.setReferences(true);
CompatibleFieldSerializer serializer = new CompatibleFieldSerializer(kryo, ClassWithDuplicateField.class);
serializer.getCompatibleFieldSerializerConfig().setChunkedEncoding(true);
serializer.getCompatibleFieldSerializerConfig().setExtendedFieldNames(false);
serializer.updateFields();
kryo.register(ClassWithDuplicateField.class, serializer);

final ClassWithDuplicateField duplicateField = new ClassWithDuplicateField();
roundTrip(31, duplicateField);
assertEquals(1, log.messages.size());
}

static class ClassWithDuplicateField extends SuperClassWithDuplicateField {
private Boolean customNote = true;
}

static class SuperClassWithDuplicateField implements Serializable {
private Boolean customNote = false;

public SuperClassWithDuplicateField() {}

public SuperClassWithDuplicateField(Boolean customNote) {
this.customNote = customNote;
}

public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
SuperClassWithDuplicateField other = (SuperClassWithDuplicateField)obj;
if (customNote != other.customNote)
return false;
return true;
}
}

public static class ClassWithObjectField {
Object value;

Expand Down