1

你如何接收序列化事件?你可以定义

void writeObject(ObjectOutputStream out) {
  // handle event
  out.defaultWriteObject(this);
}

在 java 序列化中,当您的对象被序列化时将调用此方法。你如何在 Kryo 做同样的事情?两者都有默认序列KryoSerializableExternalizable的问题:一旦调用了事件处理程序,您就需要默认的读/写对象。但是没有这样的事情!? 您可以调用FieldSerializerinread(Kryo, Input)来读取对象的字段,但它会为您生成一个新对象,而不是填充当前对象。为此,我尝试引入一个自定义序列化程序:

Serializer def = kryo.getDefaultSerializer(A.class)
kryo.addDefaultSerializer(A.class, new Serializer() {
    public void write(Kryo kryo, Output output, Object object) {
        ((A)object).serializationEvent();
        def.write(kryo, output, object);

但是,我提到通过 A 的子类接收serializationEvent()事件,只有 A.class 字段被序列化。因此,这不适用于class B extends A. 我还尝试了Natan 提出的解决方案:register(A.class, new FieldSerializer(A.class, myhandler。这会序列化所有字段,包括子类,但是根本不会为子类调用自定义序列化程序。因此,我决定 Kryo 自定义仅适用于最终课程。Nathan 说这个结论是“无效的”,而 KryoSerializable 解决方案是“特定于应用程序的”,否则认为是“粗鲁的”。尽管有这样的决心,我还是决定发表我发现的一般方法。

4

1 回答 1

1

我发现了两种解决方案。首先,覆盖 writeReferenceOrNull 可以工作

Kryo kryo = new Kryo() {
    public boolean writeReferenceOrNull (Output output, Object object, boolean mayBeNull) {
        if (object instanceof A) {
            ((A) object).serializationEvent();
        }

        return super.writeReferenceOrNull(output, object, mayBeNull);
    }

但是,它需要更改源代码可见性,Natan 说这仅在启用引用时才有效(在默认情况下),并推荐一种更可靠的方法:覆盖 newDefaultSerializer:

public class EventFiringKryo extends Kryo {
    protected Serializer newDefaultSerializer(Class type) {
        final Serializer def = super.newDefaultSerializer(type);
        Serializer custom = new Serializer() {

            public void write(Kryo kryo, Output output, Object object) {
                System.err.println("writing " + object + ":" + object.getClass().getSimpleName());
                if (object instanceof A)
                    ((A)object).serializationEvent();
                def.write(kryo, output, object);
            }

            public Object read(Kryo kryo, Input input, Class type) {
                Object result = def.read(kryo, input, type);
                if (result instanceof SomeAnotherType)
                    result.canInitializeSomethingElse();
                return result;
            }
        };
        return custom;
    }

}

除了有效之外,此方法不需要仔细注册所有实现您要调用的接口的类。

于 2012-09-07T21:03:26.967 回答