java - 反序列化时跳过新的 transient 字段

标签 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;
}

在某些时候,我意识到 A 中的 b 字段实际上不应该被持久化(并且 B 根本不应该被序列化),所以我将其更改为:

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 的反序列化跳过现在是 transient 的字段?例如,是否有一种方法可以覆盖反序列化代码在 ObjectInputStream 中读取的类描述并更新其 b 的定义,以便它知道其 transient ?

最佳答案

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

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

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

关于java - 反序列化时跳过新的 transient 字段,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2849798/

相关文章:

Java.io/Android File() 实例与实际文件系统对象,它是什么时候创建的?

java - 测试失败后评估断言消息的好模式

java - 自定义对象序列化的ArrayList

java - 为什么 Eclipse 在从 Java 接口(interface)实现方法时不包含注释?

java - 如何在Java中创建正确的实例?

java - 使用 Quartz 进行任务调度

java - 通过 TCP channel 发送大文件并进行序列化

php - 将数组打印到文件

java - java中的serialVersionUID是什么,通常在异常类中?

java - 无法使用 GSON 将复杂的 json 序列化为对象?