4

残念ながら、質問タイトルの状況は数年前にすでに発生しています。

名前とID番号のゲッターIdを拡張して含むインターフェースがあります。インターフェイスを実装Serializableする一致するクラスがあります。IdImplしかし、過去のある時点で、クラスでしたId type のメンバ フィールドを持つシリアライズ可能なコンテナ オブジェクトもありますId。これらのコンテナ オブジェクトは数年間データベースにシリアル化されているため、両方のタイプの を含むコンテナ オブジェクトのバージョンが存在しますId。古いオブジェクトを逆シリアル化しようとすると、InvalidClassException. Id古い具象クラス インスタンスを含む古いコンテナ オブジェクトをデシリアライズするにはどうすればよいですか?

完全な開示: インターフェースに対する他のいくつかの変更が何年にもわたって行われてきましたが、それらは互換性のある変更Idのように見えると思いました ( 「String idType」のフィールドと getter を追加しました; 生成されました)。これらの変更のいずれかが問題を引き起こしている可能性はありますか?IdImplIdComparable

クラスは次のようになります。

// current Id interface
public interface Id extends Serializable, Comparable<Id> {
    String getName();
    int getIdNumber();
}

// current Id implementation
public class IdImpl implements Id {
    private static final long serialVersionUID = 10329865109284L;
    private String name;
    private int idNumber;
    IdImpl(String name, int idNumber) { this.name = name; this.idNumber = idNumber; }
    @Override public String getName() { return name; }
    @Override public int getIdNumber() { return idNumber; }
    @Override public int compareTo(Id id) { /* some code here */ }
}

// the container object
public ContainerForm implements Serializable {
    private static final long serialVersionUID = -3294779665912049275L;
    private String someField;
    private Id user;
    private String someOtherField;
    // getters and setters
}

// this is what the _old_ Id concrete class looked like
// (from source control history; not in current project)
public class Id implements Serializable, Comparable {
    // never had a serialVersionUID
    private String name;
    private int idNumber;
    Id(String name, int idNumber) { this.name = name; this.idNumber = idNumber; }
    public String getName() { return name; }
    public int getIdNumber() { return idNumber; }
    public int compareTo(Object id) { /* some code here */ }
}

コンテナー オブジェクトを逆シリアル化しようとしたときに発生する例外は次のとおりです。

java.io.InvalidClassException: mypkg.people.Id; local class incompatible: stream classdesc serialVersionUID = -6494896316839337071, local class serialVersionUID = -869017349143998644
    at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:562)
    at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1583)
    at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1496)
    at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1732)
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1329)
    at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1947)
    at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1871)
    at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1753)
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1329)
    at java.io.ObjectInputStream.readObject(ObjectInputStream.java:351)
    at mypkg.forms.FormFactory.getForm(FormFactory.java:3115)
    ... 34 more
4

1 に答える 1

6

原則として、serialVersionUID を使用せずにクラスをインターフェイスに変換することは、サポートが非常に難しい移行です。

この特定の例では、次の方法で古い実装をサポートできると思います。Id

  • OldId古いserialVersionUIDと古い実装Id(実装する必要があります)を持つクラスを作成します(それを呼び出しますId)。
  • ObjectInputStream のカスタム サブクラスを作成し、readClassDescriptor()メソッドをオーバーライドします。親の readClassDescriptor を呼び出し、
    • 返された ObjectStreamClass がIdクラス名と古い serialVersionUID を持っている場合、新しいOldIdクラスの ObjectStreamClass を返します
    • それ以外の場合は、指定された記述子を返します
于 2012-08-15T16:57:26.500 に答える