2012-09-07 33 views
1

如何接收序列化事件?你可以在java序列化中定义Kryo中的序列化事件

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

并且当你的对象被序列化时这个方法会被调用。你怎么在Kryo做同样的事情? KryoSerializableExternalizable都有默认序列化的问题:一旦你调用你的事件处理程序,就需要默认的读/写对象。但是没有这样的事情! ?您可以调用 read(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); 

但是,我提到过一个子类接收serializationEvent()事件,只有的A.class领域序列化。所以,这对class B extends A不起作用。我也试过解决方案proposed by Natanregister(A.class, new FieldSerializer(A.class, myhandler。这将序列化所有字段,包括子类,但是,自定义序列化程序根本不会为子类调用。所以,我决定Kryo定制只适用于最终课程。 Nathan says that this conclusion is "invalid" and KryoSerializable solution "application-specific" and thinking otherwise "rude".尽管有这样的解决方案,我决定发布我发现的一般方法。

回答

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); 
    } 

但是,它需要的源代码的可见性变化,纳坦说,这只有当引用启用(默认情况下),并建议一个更可靠的方法来代替:重写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; 
    } 

} 

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