[英]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.