EsotericSoftware / EsotericSoftware/kryo

When entity add a field extends Collection, CompatibleFieldSerializer lost compatibility.

Open
#1,098 5 comments 0 reactions 0 assignees View on GitHub
bug duplicate help wanted kryo 6
Dominant language
HTML
Stars
6.5k
Forks
841
Avg merge
39m
Merged PRs (30d)
4

Description

**Describe the bug**

When serializing, the entity used has one additional field of type List compared to the entity used for deserialization, which throw an Exception during deserialization. I think the CompatibleFieldSerializer is supposed to handle the addition of new fields, so this situation does not meet expectations.
After briefly examining the Kryo source code, I found that the CollectionSerializer, when serializing, does not write the elementType if it has access to the elementSerializer, and uses kryo.writeObject to write the element. However, during deserialization, kryo.getGenerics().nextGenericClass() returns null and the elementSerializer cannot be obtained, so kryo.readClassAndObject is used to read, which seems to be causing the problem.

**To Reproduce**
Please delete PoJo.list when deserializing
```java
// KryoFactory
public class CompatibleKryoFactory {

private static final int MAX_CAPACITY = 8;
private final Pool kryoPool;
/**
* using zero args constructor as default
* if not exists, fallback using ASM
*/
private static final InstantiatorStrategy STRATEGY =
new DefaultInstantiatorStrategy(new StdInstantiatorStrategy());

public CompatibleKryoFactory() {
kryoPool = new Pool(true, true, MAX_CAPACITY) {
@Override
protected Kryo create() {
Kryo kryo = new Kryo();
init(kryo);
return kryo;
}
};
}

public Kryo obtain() {
return kryoPool.obtain();
}

public void free(Kryo kryo) {
kryoPool.free(kryo);
}

protected void init(Kryo kryo) {
kryo.setReferences(false);
kryo.setRegistrationRequired(false);
kryo.setInstantiatorStrategy(STRATEGY);
kryo.setDefaultSerializer(CompatibleFieldSerializer.class);
}
}
```

```java
// entity
@Data
public class PoJo {
private String str;
private int i;
// delete when deserializing
private List list;
}

```

```java
// Serializer
public class SerializerTest {

public static final CompatibleKryoFactory FACTORY = new CompatibleKryoFactory();

public static void main(String[] args) {
PoJo poJo = new PoJo();
poJo.setI(1);
poJo.setStr("test");
List list = new ArrayList<>();
list.add("hello");
poJo.setList(list);

Kryo kryo = FACTORY.obtain();

try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
Output output = new Output(outputStream);
kryo.writeClassAndObject(output, poJo);
output.flush();
System.out.println(Base64.getEncoder().encodeToString(outputStream.toByteArray()));
output.close();
} catch (Exception e) {
log.error("failed", e);
} finally {
FACTORY.free(kryo);
}

}
}
```

```java
// Deserializer
public class DeserializerTest {
public static void main(String[] args) {
Kryo kryo = SerializerTest.FACTORY.obtain();

String str = "AQBjb20udGVzdC5Qb0rvA4JpbGlz9HN08gICAQFqYXZhLnV0aWwuQXJyYXlMaXP0AmhlbGzvA3Rlc/Q=";
byte[] bytes = Base64.getDecoder().decode(str);
try (ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes);) {
Input input = new Input(inputStream);
PoJo poJo = (PoJo) kryo.readClassAndObject(input);
System.out.println(poJo);
} catch (Exception e) {
log.error("failed", e);
} finally {
SerializerTest.FACTORY.free(kryo);
}
}

}
```
**Environment:**
- OS: win10
- JDK Version: 11
- Kryo Version: 5.6.0

**Additional context**
Add any other context about the problem here.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.