您如何收到序列化事件?你可以定义
void writeObject(ObjectOutputStream out) {
// handle event
out.defaultWriteObject(this);
}
在java序列化中,当您的对象被序列化时,将调用此方法。你怎么在Kryo做同样的事情? KryoSerializable
和Externalizable
都存在默认序列化的问题:一旦调用了事件处理程序,就需要默认的读/写对象。但是没有这样的事情! ?您可以在FieldSerializer
中调用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);
但是,我提到通过A的子类接收serializationEvent()
事件,只有A.class字段被序列化。因此,这对class B extends A
不起作用。我还尝试了解决方案proposed by Natan:register(A.class, new FieldSerializer(A.class, myhandler
。这会序列化所有字段,包括子类,但根本不会为子类调用自定义序列化程序。因此,我认为Kryo定制仅适用于最终课程。 Nathan says that this conclusion is "invalid" and KryoSerializable solution "application-specific" and thinking otherwise "rude".尽管有这样的解决方案,我还是决定发布我发现的一般方法。
答案 0 :(得分: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;
}
}
除了有效之外,此方法不需要仔细注册实现将要调用的接口的所有类。