EsotericSoftware / kryo

Java binary serialization and cloning: fast, efficient, automatic
BSD 3-Clause "New" or "Revised" License
6.19k stars 824 forks source link

ExternalizableSerializer does not support circular references #1094

Open mikehearn opened 3 months ago

mikehearn commented 3 months ago

Describe the bug

If an object implements Externalizable and is registered with the ExternalizableSerializer, there is no way for it to call kryo.reference() on itself and the ExternalizableSerializer doesn't do this either. As a consequence, if the Externalizable attempts to read a reference to itself, it will get null and deserialize incorrectly.

To Reproduce

Provide a minimal reproducible example of the problem, ideally in the form of a runnable test-case.

import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;
import com.esotericsoftware.kryo.serializers.ExternalizableSerializer;

import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;

public class ExternalizableBugProof {
    static class Example implements Externalizable {

        @Override
        public void writeExternal(ObjectOutput out) throws IOException {
            out.writeUTF("abc");
            out.writeObject(this);
        }

        @Override
        public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
            in.readUTF();
            Object obj = in.readObject();
            assert obj == this : "" + obj;
        }
    }

    public static void main(String[] args) {
        var kryo = new Kryo();
        kryo.setReferences(true);
        kryo.setRegistrationRequired(false);
        kryo.addDefaultSerializer(ExternalizableBugProof.Example.class, ExternalizableSerializer.class);

        var output = new Output(1024);
        kryo.writeObject(output, new Example());
        kryo.readObject(new Input(output.getBuffer()), Example.class);
    }
}

Environment:

Kryo 5.6.0

theigl commented 3 months ago

The ExternalizableSerializer has not been touched in a very long time. I'm guessing that not many people are using it. What use case do you have that prevents you from using FieldSerializer or KryoSerializable?

mikehearn commented 3 months ago

An object that wants to define its own serialization format independent of Kryo so it can ensure backwards compatibility as it evolves over time.