反序列化时跳过新瞬态字段

时间:2010-05-17 14:22:05

标签: java serialization

我继承了以下代码(以及使用它存储的数据,即A的序列化实例):

class A implements Serializable {
  private static final long serialVersionUID = 1L;
  int someField;
  B b;
}

class B implements Serializable {
  private static final long serialVersionUID = 1L;
  int someField;
}

在某些时候,我意识到b中的A字段实际上不应该被保留(并且B根本不应该是可序列化的),所以我将事情改为:< / p>

class A implements Serializable {
  private static final long serialVersionUID = 1L;
  int someField;
  transient B b;
}

class B {
  int someField;
}

如果我创建A的新实例并将其序列化,我可以顺利地对其进行反序列化。但是,如果我尝试反序列化使用旧代码存储的A实例,我会得到表单的例外:

java.io.InvalidClassException: B; B; class invalid for deserialization
  at java.io.ObjectStreamClass.checkDeserialize(Unknown Source)
  at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
  at java.io.ObjectInputStream.readObject0(Unknown Source)
  at java.io.ObjectInputStream.defaultReadFields(Unknown Source)
  at java.io.ObjectInputStream.readSerialData(Unknown Source)
  at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
  at java.io.ObjectInputStream.readObject0(Unknown Source)
  at java.io.ObjectInputStream.readObject(Unknown Source)

我认为这是因为持久化数据还存储了AB的类描述,并且仍然认为b是持久的,即使在当前它们不再是版本(参见ObjectStreamClass中的第600至606行)

有没有办法强制A的反序列化跳过现在是瞬态的字段?例如,有没有办法覆盖反序列化代码在ObjectInputStream中读取的类描述并更新其b的定义,以便它知道它的瞬态?

2 个答案:

答案 0 :(得分:2)

在反序列化期间,没有技巧可以跳过某些字段。实际上,(几乎)您对类的源代码所做的任何更改都会使旧的序列化数据无法反序列化。序列化将源代码非常紧密地耦合到序列化数据。

这就是序列化不适合长期数据存储的原因。序列化仅适用于RMI(通过网络传输对象)或磁盘上的临时存储之类的东西。使用记录完备的(标准)文件格式而不是Java序列化来进行长期数据存储。

您可以做的是使用旧代码对数据进行反序列化,然后将其写入另一种格式,然后再使用该格式。

答案 1 :(得分:0)

这就是为什么使用序列化进行长期对象存储是个坏主意。在您的情况下,我认为将B保留为Serializable(即使A中的引用是暂时的)足以解决您的问题。

此外,您可能希望实现自己的readObject方法,以便在它带有旧数据的情况下将B归零。

我不知道是否可以实现一个自定义的readObject方法,它实际上会在遇到这样的错误时恢复类。它肯定会非常混乱。