[英]Java de-serialization backward compatibility
如何反序列化在序列化后修改的類?
更具體地說,我知道當類的初始版本中具有serialVersionUID
時,可以完成此操作。 有什么方法可以對沒有serialVersionUID
類執行此操作?
我有一個對象
package com.test.serialize;
import java.io.Serializable;
public class MyObject implements Serializable{
String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
我像這樣序列化類
package com.test.serialize;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
public class SerializeTest {
public static void main(String[] args) {
try {
MyObject myObject = new MyObject();
myObject.setName("Ajit");
ObjectOutputStream objectOStr = null;
ByteArrayOutputStream byteOStr = null;
try {
byteOStr = new ByteArrayOutputStream();
objectOStr = new ObjectOutputStream(byteOStr);
objectOStr.writeObject(myObject);
} catch (IOException e) {
System.out.println(e);
} finally {
try {
if (objectOStr != null)
objectOStr.close();
} catch (IOException e2) {
}
}
FileOutputStream fo = new FileOutputStream(new File("serialize"));
fo.write(byteOStr.toByteArray());
fo.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
像這樣反序列化
package com.test.serialize;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.RandomAccessFile;
public class DeserializeTest {
public static void main(String[] args) {
try {
// File f = new File("serialize");
// FileInputStream fs = new FileInputStream(f);
RandomAccessFile raF = new RandomAccessFile("serialize", "r");
byte[] b = new byte[(int)raF.length()];
raF.read(b);
ObjectInputStream oIstream = null;
ByteArrayInputStream bIstream = null;
bIstream = new ByteArrayInputStream(b);
oIstream = new ObjectInputStream(bIstream);
Object finalResult = oIstream.readObject();
System.out.println(finalResult.toString());
} catch (IOException | ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
一段時間后,我添加了
@Override
public String toString() {
return "MyObject [name=" + name + ", names=" + names + "]";
}
到MyObject
。 在添加之后,我得到了類似的異常
java.io.InvalidClassException: com.test.serialize.MyObject; local class in
compatible: stream classdesc serialVersionUID = 5512234731442983181, local class
serialVersionUID = -6186454222601982895
at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:617)
at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1622)
at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1517)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1771)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1350)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:370)
at com.test.serialize.DeserializeTest.main(DeserializeTest.java:25)
請幫我解決一下這個。
感謝@GáborBakos。
這可以通過為較舊的類創建serialVersionUID來解決(其簽名應與序列化期間的簽名相同),然后在當前類中添加該serialVersionUID。
serialver -classpath /***PATH***/bin com.test.serialize.MyObject
那回來了
com.test.serialize.MyObject: static final long serialVersionUID = 5512234731442983181L;
之后,我將其添加到我的MyObject中,如下所示
package com.test.serialize;
import java.io.Serializable;
public class MyObject implements Serializable{
/**
* Added serial version Id of old class, created before adding new fields
*/
private static final long serialVersionUID = 5512234731442983181L;
public MyObject() {
System.out.println("Constructor");
}
String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
String names ="Altered after change!";
public String getNames() {
return names;
}
public void setNames(String names) {
System.out.println("Setting names");
this.names = names;
}
@Override
public String toString() {
return "MyObject [name=" + name + ", names=" + names + "]";
}
}
工作正常。
更多信息請參考: serialver
第一個建議:使用序列化,因為一切都差不多了。
第二條建議:使用serialVersionUID並使用一個版本對其進行修復:在這里警告您並防止在不同序列化版本之間造成混淆。
因此:如果更改字段或字段的含義,請更改serialVersionUID。
然后您有向后兼容性問題。
請參閱以下內容以獲得許多想法: 管理序列化Java對象的多個版本
恕我直言:
無論采用哪種解決方案,請記住您的程序將使用部分數據來管理對象:然后,您必須使用或不使用數據來管理所有案例。
如果您不經常更改版本,請使用幾個不同的類。 也許是子類或接口的實現:然后,您可以獲取程序,並管理多個版本的對象:MyClass_V1,MyClass_V2等。反序列化時,可以測試/重試並獲得良好的Object。 之后,您可能必須在各個類之間轉換數據
如果您更改版本,則通過添加新字段(而不更改舊字段),會稍微容易一些(子類,直接轉換為父級)
或者您可以考慮使用XML結構進行序列化和反序列化:您可以具有向后和向前的兼容性,因為它是可擴展的 :字段存在或為空。 您必須自己管理映射或使用一些庫。
希望能幫助到你 !
我會記住以下幾點,
Serializable
類都包含一個serialVersionUID
(是否明確指定了一個都沒有關系)。 toString()
方法后更改了serialVersionUID
) 3,在修改類之前,可以使用serialver實用工具找到舊類的serialVersionUID
並在新類中使用它
不要以為還有其他魔術:)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.