10

質問

非一時的なブールフィールドを持つ Serializable クラス (A と呼びましょう) と、同じフィールドが一時的である必要があるサブクラス (B) があります。これどうやってするの?

より正確には、B をデシリアライズするときにフィールドをデフォルトのブール値 ( false) に復元したいのですが、A をデシリアライズするときに正しい値に復元したいと考えています。それにもかかわらず、A から継承された他のフィールドは復元する必要があります。

機能的には、A はセッション間で復元されるオブジェクトを表し、B は特定のタイプの A であり、その状態は新しいセッションごとにリセットされる必要があります。

簡単なコード サンプル:

public class A implements java.io.Serializable {

    private String label;
    // non-transient
    private boolean field;

    public String getLabel() {
        return label;
    }

    public void setLabel(String label) {
        this.label = label;
    }

    public boolean isField() {
        return field;
    }

    public void setField(boolean field) {
        this.field = field;
    }
}

public class B extends A {
    // field should be transient for this class
    // label should remain non-transient
}

保持しないことを選択したいくつかの可能な解決策

  • 簡単な解決策は、 に変更B extends AA extends B、フィールドをトランジェントにし、writeObject()A に a を追加してフィールドをシリアル化することです。ただし、B extends A機能的な意味があり、元に戻すことが賢明であるとは確信していません。

  • readObject()フィールドの逆シリアル化された値を上書きするメソッドを実装できます。ただし、これは汚い解決策のように感じます。他に選択肢がない限り、これを使用したくありません。

  • 一時的なフィールドをエミュレートするメソッドを作成しようとしましたwriteObject()が、機能せず、理由もわかりません。誰かが手がかりを持っているなら、それが私の解決策かもしれません:

public class B extends A {
    private void writeObject(ObjectOutputStream out) throws IOException {
        // save current state
        boolean field = isField();

        // synchronized to make sure this instance is not interrogated
        // while changed for serialization
        synchronized (this) {
            // emulate transient state and serialize
            setField(false);
            out.defaultWriteObject();

            // restore state
            setField(field);
        }
    }
}
  • 編集:シャドウイングを使用した@rocketboyのソリューションは機能しますが、未使用のフィールドが1つ残るため、シャドウイングには不快です(Aの非一時的なフィールドは使用されず、Bの一時的なバージョンは読み書きされます)。解決策かもしれませんが。経験豊富な Java 開発者は、これがクリーンなソリューションだと思いますか?
public class B extends A {
    // shadow A's field
    private transient boolean field;

    @Override
    public boolean getField() {
        return field;
    }

    @Override
    public void setField(boolean field) {
        this.field = field;
    }
}

答え

@ m1o2 のアドバイスに従って、Externalizableインターフェイスを使用してソリューションを実装することができました。

public class B extends A implements java.io.Externalizable {

    // Do not forget to have a public no-arg constructor
    // for Serialization to work
    public B() {
    }

    @Override
    public void writeExternal(ObjectOutput out) throws IOException {
        // Write only the fields I am interested in
        out.writeObject(getLabel());
    }

    @Override
    public void readExternal(ObjectInput in) throws IOException,
            ClassNotFoundException {
        // Read the serialized fields IN THE ORDER THEY WERE WRITTEN
        setLabel((String) in.readObject());
    }
}

ただし、A と B は単純なクラスであるため、これが適用されることに注意してください。多くのフィールドがあり、進化する傾向があるクラスの場合、これはより多くのコストがかかる可能性があります (リフレクションに基づくコードを使用する場合を除く)。

4

1 に答える 1