2017-04-16 114 views
0

我有一个应用程序以前通过序列化模型对象存储了一些数据(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对象?无论QuickNoteOldQuickNote是相同的,只是QuickNote不再实行SerializableOldQuickNote一样。

我的确尝试寻找答案,但说实话,我甚至不知道如何搜索这个,因为当我选择首先序列化QuickNote对象时,我显然做出了糟糕的设计决定。

注意事项:

  1. 我不能序列化对象改变对象类型(类名),因为它是目前驻留在用户的系统中。
  2. QuickNote对象不能改变,以实现Serializable,因为它的注解和用于编组JAXB。
+0

最简单的(只有?)解决方案是让它再次实现'Serializable'。 – Henry

+0

我只是在我的问题中添加了一些警告。我不能用新对象实现'Serializable',因为JAXB编组似乎不允许它使用'Serializable'对象。 – Zephyr

+0

欢迎来到Java对象序列化的世界 - 这些问题是我一般不推荐使用Java对象序列化的原因。 – Robert

回答

0

这在评论中得到了回答,但答案并未如此发布。

我最终将旧类移动到不同的包中,并在用户再次运行程序时转换类。

我只需要等待我的用户全部更新新版本并删除旧版本。

谢谢!

1

在评论中提到了一个选项:强制将数据迁移到XML,然后摆脱旧的类。

另一种方法是尝试分析它没有Java序列机械的使用。有一些工具可以解析java序列化数据,例如https://github.com/gagern/nodeJavaDeserialization 虽然我在java中找不到任何库,但是如果只有一个类数据要解析,解析它的任务看起来并不那么可怕。该格式的文档可用:http://docs.oracle.com/javase/6/docs/platform/serialization/spec/serialTOC.htmlObjectOutputStream/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()); 

此打印 '你好'。你可以看到,在这里,我通过一个类序列化并通过另一个序列化,通过改变序列化形式的类的名称(索引为12的字节被更改,它存储'1'的位置),反序列化。

对于这项工作,以下必须持有:

  1. 这两个类(老QuickNoteQuickNot2必须具有相同的结构
  2. 他们都必须具有相同的serialVersionUID,所以如果不是你需要找到它并在你的代码中指定它,为了找到它,你可以在你的QuickNot2类中设置一些任意值,并查看由解串器产生的错误消息中的值。

QuickNot2建议离开班级名称长度不变。看起来有可能完全改变这个类名,它的长度,我只是没有检查这个。

相关问题