我们正在序列化一些Data对象并将它们存储在数据库中。长期以来,数据库中有数百个这样的对象。最近我们需要改变其中一个类的结构。现在反序列化这些对象就是抛出错误。
我们之前没有编写自定义序列化和反序列化。使用defaultSerialVersionUID
也无法帮助我们,因为在序列化时它只是默认1L
。
在基础类结构发生变化后,有没有更好的方法来反序列化它们?
答案 0 :(得分:3)
这是一个很大的错误,IMO。您避免了必须构建和维护与数据对象相对应的表...但Java对象序列化不是为此类设计的,而这种脆弱性是缺点之一。我们正在序列化一些Data对象并将它们存储在数据库中......
@EJP和@ sidoh的答案提供了一些想法,可以让你自己从目前的洞中挖掘出来,只要你能掌握旧版本的课程。有几种方法:
在破坏兼容性的更改之前回滚到代码/架构状态...并以避免错误的方式重做工作。
不要回滚,而是编写一些ad-hoc转换器,将当前可读对象加载到可读形式中并更新存储的版本。
前者可能不切实际;例如如果其他地方发生了太多变化,或者您的代码/数据正在生产中。
后者涉及从版本控制中检索类的旧版本和新版本,并构建使用旧类加载的ad-hoc转换器,转换为新类和保存的实例。这样做的难点在于构建一个可以同时在同一个JVM中使用相同类的两个不同版本的Java应用程序:
您可以在类路径上实例化两个具有不同版本的类加载器。但问题是JVM会将这两组类视为不同类型,这样就不可能对这两个版本进行静态绑定。你可以通过反思来解决这个问题......但是它会非常混乱,特别是如果相应的对象API很广泛。
您可以将此作为两个阶段的过程。第1阶段是使用旧类加载,然后使用(比如)写入文件的JSON序列化类(比方说)。第2阶段是读取JSON,使用它来使用新类创建对象,并使用对象序列化对它们进行序列化。
第三种方法是编写一个ad-hoc转换器,调整序列化对象。基本上,您需要了解旧的和新的序列化表单之间的差异,然后通过使用一些低级API读取/写入来重写序列化对象。这种方法的一个变体是在新版本的类中实现自定义readObject和方法,该类可以理解旧格式和新格式。但是,考虑到旧对象没有任何自定义版本字段,这可能很棘手。应该注意的是,这种东西超出了序列化规范的范围......
但IMO最好的替代方案是使用它作为停止使用Java序列化的机会。使用旧类读取对象,然后将它们写回常规SQL表中,作为JSON或XML blob,或使用ORM映射。
答案 1 :(得分:2)
展望未来,我强烈推荐像Thrift这样的东西。它的开发部分是为了解决这个问题。
至于解决手头的问题,你能否恢复变化?反序列化对象,将旧数据中的字段放入新对象,并序列化新对象。
答案 2 :(得分:1)
在执行这些更改之前,您应该首先阅读是对象序列化规范的对象版本控制章节。它在保留与现有序列化的兼容性的同时,准确地列出了您可以做什么和不能做什么。它允许比大多数人想象的要多得多,但它不允许例如继承链的变化,这听起来就像你已经完成的那样。
您需要做的第二件事是退出那些不符合的变化。