如何反序列化序列化后修改的类?
更具体地说,我知道当一个类在其初始版本中有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)
请帮助我。
答案 0 :(得分:1)
谢谢@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
答案 1 :(得分:0)
第一个建议:使用序列化,因为一切都已基本完成。
第二条建议:使用serialVersionUID并使用一个版本进行修复:它是为了警告您并防止不同序列化版本之间的混淆。
所以:如果更改字段的字段或含义,请更改serialVersionUID。
然后你有向后兼容性问题。
有很多想法,请参阅此内容:Managing several versions of serialized Java objects
IMHO:
无论采取何种解决方案,请记住,您的程序将管理具有部分数据的对象:然后您必须管理所有包含或不包含数据的情况。
如果你不经常改变你的版本:使用几个不同的类。也许子类或接口的实现:然后你可以获得你的程序,并管理几个版本的对象:MyClass_V1,MyClass_V2等。反序列化时,你可以测试/重试并获得好的Object。之后,您可能必须在类之间转换数据
如果您通过添加新字段(不更改旧字段)来更改您的版本,则更容易一些(子类,转换直接转换为父级)
或者您可以考虑使用XML结构来序列化和反序列化:您可以具有向后和向前兼容性,因为它是可扩展:字段在那里,或者为null。您必须自己管理映射或使用一些库。
希望它有所帮助!
答案 2 :(得分:-1)
我会记得以下几点,
Serializable
类都包含serialVersionUID
(如果您明确指定了一个,则无关紧要)。 serialVersionUID
方法后toString()
已更改) 3.在修改类之前,您可以使用 serialver 实用程序查找旧类的serialVersionUID
并在新类中使用
不要认为还有其他任何魔术技巧:)