如何将对象反序列化为具有相同名称的新对象?

时间:2017-04-16 13:32:44

标签: java serialization

我有一个应用程序,它先前通过序列化模型对象(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编组。

2 个答案:

答案 0 :(得分:1)

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

另一种选择是尝试在不使用Java Serialization机制的情况下解析它。有一些工具可以解析像https://github.com/gagern/nodeJavaDeserialization这样的java序列化数据 我在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());

打印&#39; hello&#39;。

正如您所看到的,这里我通过一个类进行序列化,并通过更改序列化表单中类的名称来反序列化另一个类(带有索引12的字节已更改,它&#39; 1&#39; 1&# 39;存储)。

为此,必须遵守以下规定:

  1. 两个类(旧QuickNoteQuickNot2必须具有相同的结构
  2. 它们必须具有相同的serialVersionUID,因此如果未明确写入代码,则需要找到它并在代码中指定它。要找到它,您可以在QuickNot2类中设置一些任意值,并查看由反序列化程序生成的错误消息中的值。
  3. 建议

    QuickNot2保持类名长度不变。似乎可以用它的长度完全改变类名,我只是没有检查它。

答案 1 :(得分:0)

评论中回答了这个问题,但答案中的答案并没有这样说。

我最终将旧类移动到另一个包,并在用户再次运行程序时转换了类。

我所要做的就是等待我的用户全部更新新版本并删除旧版本。

谢谢!