Skip to content

Deserialization fails with "Buffer underflow" after add a new field to record class (Issue with backward compatibility) #1012

Description

@investr777

Kryo version 5.5.0
Java 17

When data was serialized and after that a new field was added, deserilization fails with exception: com.esotericsoftware.kryo.kryo5.io.KryoBufferUnderflowException: Buffer underflow
Stacktrace

Exception in thread "main" com.esotericsoftware.kryo.kryo5.io.KryoBufferUnderflowException: Buffer underflow.
Serialization trace:
info (akta.dcs.session.live.hash.Data)
	at com.esotericsoftware.kryo.kryo5.io.Input.require(Input.java:221)
	at com.esotericsoftware.kryo.kryo5.io.Input.readVarIntFlag(Input.java:482)
	at com.esotericsoftware.kryo.kryo5.io.Input.readString(Input.java:777)
	at com.esotericsoftware.kryo.kryo5.serializers.DefaultSerializers$StringSerializer.read(DefaultSerializers.java:174)
	at com.esotericsoftware.kryo.kryo5.serializers.DefaultSerializers$StringSerializer.read(DefaultSerializers.java:164)
	at com.esotericsoftware.kryo.kryo5.Kryo.readObjectOrNull(Kryo.java:826)
	at com.esotericsoftware.kryo.kryo5.serializers.RecordSerializer.read(RecordSerializer.java:136)
	at com.esotericsoftware.kryo.kryo5.Kryo.readObject(Kryo.java:777)

Code example:

public record Data(
    String id
){}

===============================================
var kryoLocal = ThreadLocal.withInitial(() -> {
    Kryo kryo = new Kryo();
    kryo.setRegistrationRequired(false);
    kryo.setDefaultSerializer(CompatibleFieldSerializer.class);
    return kryo;
});

 var data = new Data("1");

  var output = new Output(1024, -1);
  kryoLocal.get().writeObject(output, data);
  output.flush();
  var serializedData = output.toBytes(); // [-126, 49]
  output.close();

After serialized, new field was added:

public record Data(
    String id,
   String info
){}

=================

var input = new Input(new byte[] {-126, 49});
var deserializedData = kryoLocal.get().readObject(input, Data.class);
input.close();

And eventually an exception is thrown: com.esotericsoftware.kryo.kryo5.io.KryoBufferUnderflowException: Buffer underflow.

But if convert Java record to class, everything works properly:
Code example:

public class Data {
    private String id;

    public Data() {
    }

    public Data(
        String id
    ) {
        this.id = id;
    }

    public String id() {
        return id;
    }
}

=====================================
var kryoLocal = ThreadLocal.withInitial(() -> {
            Kryo kryo = new Kryo();
            kryo.setRegistrationRequired(false);
            kryo.setDefaultSerializer(CompatibleFieldSerializer.class);
            return kryo;
        });

        var data = new Data("1");

        var output = new Output(1024, -1);
        kryoLocal.get().writeObject(output, data);
        output.flush();
        var serializedData = output.toBytes(); // [1, 105, -28, 3, -126, 49]
        output.close();

After serialized, new field was added:

public class Data {
    private String id;
    private String info;

    public Data() {
    }

    public Data(
        String id,
        String info
    ) {
        this.id = id;
        this.info = info;
    }

    public String id() {
        return id;
    }

    public String info() {
        return info;
    }
}

==========================================

var input = new Input(new byte[] {1, 105, -28, 3, -126, 49});
var deserializedData = kryoLocal.get().readObject(input, Data.class);
input.close();

As we can see, that serialized record and class have different bytes.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions