apache / apache/ignite

How to deserialize a class with final field, like Record class

Open
#10,846 0 comments 5 reactions 0 assignees View on GitHub
Dominant language
Java
Stars
5.1k
Forks
1.9k
Avg merge
3d 2h
Merged PRs (30d)
46

Description

I have a class

```java
public record Coordinate(
Integer id,
Integer x,
Integer y,
Integer z
) {}
```

It will report an exception when using when use `cache.get(key)` , the cache type is `org.apache.ignite.IgniteCache cache`
exception is:
```
Caused by: class org.apache.ignite.binary.BinaryObjectException: Failed to deserialize object [typeName=com.me.boot.dataignite.boot.dto.Coordinate]
Caused by: class org.apache.ignite.binary.BinaryObjectException: Failed to read field [name=id]
Caused by: class org.apache.ignite.binary.BinaryObjectException: Failed to set value for field: private final java.lang.Integer com.me.boot.dataignite.boot.dto.Coordinate.id
Caused by: java.lang.IllegalAccessException: Can not set final java.lang.Integer field com.me.boot.dataignite.boot.dto.Coordinate.id to java.lang.Integer
```

then when I debug, find `org.apache.ignite.internal.binary.BinaryClassDescriptor#read`, in `switch (mode) case OBJECT:`:
The process of deserialization is to use `res = newInstance()` create res first, and then in `info.read(res, reader)` use `field.set(obj, val)` set field value, **but when Field is final, an exception will be throws**

For the Record class, I currently add a piece of code to solve the deserialization problem:

```java
case OBJECT:
if (Record.class.isAssignableFrom(cls)) {
// the record class default has All-args constructor
// read all field value to Object[] values
Object[] values = new Object[fields.length];
for (int i = 0; i < fields.length; i++) {
BinaryFieldAccessor fieldAccessor = fields[i];
Object val = reader.readField(fieldAccessor.id);
values[i] = val;
}
// invoke All-args constructor to create res
Constructor constructor = cls.getDeclaredConstructors()[0];
res = constructor.newInstance(values);
} else {
res = newInstance();
reader.setHandle(res);
for (BinaryFieldAccessor info : fields)
info.read(res, reader);
}
break;
```

But besides this way, is there any other way?

- like only `@Override org.apache.ignite.internal.binary.BinaryClassDescriptor#read` and use it, no need to modify dependent source code
- like set BinaryConfiguration, but `setSerializer(BinarySerializer serializer)` doesn't seem to work

Contributor guide

Open the contributing guide

Research direction

Start with org.apache.ignite.internal.binary.BinaryClassDescriptor#read and its OBJECT branch, then inspect BinaryFieldAccessor and the BinarySerializer configuration mentioned in the report. Reproduce deserialization of the Coordinate record and determine the supported path for final fields. Done means record values deserialize without the IllegalAccessException and the resulting configuration or implementation behavior is documented.

Written by the indexing model from the issue text.

Assessment

Tech stack
java
Domain
databases
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
30/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.