2
不幸的是,問題題目的情況已經發生了好幾年。如何在將類重構爲Java中的接口時支持向後兼容的序列化?
我有一個Id
接口,它擴展了Serializable
幷包含名字和id號的getter。有一個匹配的IdImpl
類實現了接口。但是,在過去的某個時刻,Id
是的類。還有一個可序列化的容器對象,它具有Id
類型的成員字段。這些容器對象已經被序列化到數據庫已有好幾年了,所以容器對象的版本都包含這兩種類型的Id
。當試圖反序列化舊對象時,我們得到一個InvalidClassException
。如何反序列化包含舊的Id
具體類實例的舊容器對象?
披露:到Id
接口一對夫婦的其他變化已經取得了多年,但我認爲他們看起來像compatible changes(加入IdImpl
場和消氣劑Id
爲「字符串idType」;泛型Comparable
) 。其中一個變化是否也會導致問題?
的類是這個樣子:
// 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
感謝領導我到解決方案。我創建了一個'OldId'類,但是重載'resolveClass'不起作用,因爲'ObjectInputStream'抱怨這個類的名字與流中聲明的不匹配。我結束了[重寫'readClassDescriptor'來代替返回一個不同的'ObjectStreamClass'](http://www.norwinter.com/2009/08/20/refactor-serializable-java-class/)。 – matts 2012-08-15 18:42:53
@matts - sweet,我會爲未來的讀者更新我的答案。 – jtahlborn 2012-08-15 20:38:28