我有一个应用程序,它先前通过序列化模型对象(QuickNote
)来存储一些数据。然后通过反序列化加载它。
但是,我正在更新应用程序以通过XML存储数据,我需要能够导入旧的序列化对象进行转换。 不实施Serializable
的新对象也具有相同的名称。(QuickNote
)。
我正在尝试反序列化旧QuickNote
并使用以下代码将其存储到新版本中:
FileInputStream fileIn = new FileInputStream("data/quicknotes_user.dat");
ObjectInputStream in = new ObjectInputStream(fileIn);
List<OldQuickNote> newList = (List<OldQuickNote>) in.readObject();
由于旧序列化文件的类名称为QuickNote
,因为新类具有相同名称且未实现java.io.InvalidClassException: model.QuickNote; class invalid for deserialization
,因此出现错误Serializable
。
有没有办法将此QuickNote
对象反序列化为OldQuickNote
对象? QuickNote
和OldQuickNote
都相同,只是QuickNote
不再实现Serializable
,OldQuickNote
不再实现。
我确实试图寻找答案,但说实话,我甚至不确定如何搜索这个,因为我在选择序列化QuickNote
对象时显然做出了糟糕的设计决定。
警告:
QuickNote
对象以实现Serializable
,因为它已注释并用于JAXB编组。答案 0 :(得分:1)
评论中提到了一个选项:强制将数据迁移到XML,然后删除旧类。
另一种选择是尝试在不使用Java Serialization机制的情况下解析它。有一些工具可以解析像https://github.com/gagern/nodeJavaDeserialization这样的java序列化数据
我在Java中找不到任何库,但是,如果你只有一个类数据要解析,那么解析它的任务看起来并不那么可怕。该格式的文档可用:http://docs.oracle.com/javase/6/docs/platform/serialization/spec/serialTOC.html和ObjectOutputStream
/ ObjectInputStream
来源。
另一个选择是在反序列化之前使用序列化数据。想象一下,您将现有的QuickNote
重命名为QuickNot2
(丑陋,但稍后会有用),并将您的新课程设为QuickNote
。然后,在反序列化QuickNot2
之前,将序列化字节表示中的e
更改为2
。这是一个概念证明:
public class Data1 implements Serializable {
private final static long serialVersionUID = 123L;
private final String name;
public Data1(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
public class Data2 implements Serializable {
private final static long serialVersionUID = 123L;
private final String name;
public Data2(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
和
Data1 data1 = new Data1("hello");
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream dos = new ObjectOutputStream(baos);
dos.writeObject(data1);
dos.close();
byte[] serialized = baos.toByteArray();
serialized[12] = '2';
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(serialized));
Data2 data2 = (Data2) ois.readObject();
System.out.println(data2.getName());
打印&#39; hello&#39;。
正如您所看到的,这里我通过一个类进行序列化,并通过更改序列化表单中类的名称来反序列化另一个类(带有索引12的字节已更改,它&#39; 1&#39; 1&# 39;存储)。
为此,必须遵守以下规定:
QuickNote
和QuickNot2
必须具有相同的结构serialVersionUID
,因此如果未明确写入代码,则需要找到它并在代码中指定它。要找到它,您可以在QuickNot2
类中设置一些任意值,并查看由反序列化程序生成的错误消息中的值。 QuickNot2
保持类名长度不变。似乎可以用它的长度完全改变类名,我只是没有检查它。
答案 1 :(得分:0)
评论中回答了这个问题,但答案中的答案并没有这样说。
我最终将旧类移动到另一个包,并在用户再次运行程序时转换了类。
我所要做的就是等待我的用户全部更新新版本并删除旧版本。
谢谢!