1

シリアル化イベントをどのように受け取りますか? 定義できます

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

Javaシリアライゼーションでは、このメソッドはオブジェクトがシリアライズされるときに呼び出されます。Kryoで同じことをどのように行いますか? と の両方KryoSerializableExternalizableデフォルトのシリアル化の問題があります。イベント ハンドラーを呼び出すと、デフォルトの読み取り/書き込みオブジェクトが必要になります。しかし、そんなことはありません!? FieldSerializerinを呼び出し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 ANatan が提案した解決策も試しましたregister(A.class, new FieldSerializer(A.class, myhandler。これにより、サブクラスを含むすべてのフィールドがシリアル化されますが、カスタム シリアライザーはサブクラスに対してまったく呼び出されません。そのため、Kryo のカスタマイズは最終クラスでのみ機能することにしました。ネイサンは、この結論は「無効」であり、KryoSerializable ソリューションは「アプリケーション固有」であり、そうでなければ「失礼」だと考えています。そのような解決策にもかかわらず、私は発見した一般的な方法を公開することにしました.

4

1 に答える 1

1

私は2つの解決策を発見しました。最初は、 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 に答える