Java反序列化,将字段更改为 transient

标签 java serialization

背景

我有一个类,它没有覆盖任何序列化功能,也没有 serialVersionUID,但它仍然被序列化、存储,然后反序列化。这是一个配置对象,当更改配置时,数据实际上是从配置 UI 中读取的,然后通常“从头开始”创建对象并序列化以进行存储。只有在使用时,才会通过反序列化创建对象。

现在有两个字段被添加到这个类中,它们不应该被序列化,但是......这当然会导致一些反序列化问题(NullPointerException 当字段在默认反序列化后保留为空时,破坏类不变量),解决了通过打开配置 UI 并保存配置,从而保存对象的正确序列化形式。

问题

现在,如果我以这些方式之一修改类以进行快速修复,从保存的配置数据反序列化对象会发生什么:

  1. 去掉这些字段,保存的数据是新版本的,里面有这些字段吗?
  2. 把这些字段改成transient,保存的数据是新版本的,里面有这些字段?
  3. 将这些字段更改为 transient ,保存的数据是旧版本,没有这些字段?

为了使这个更具体,假设添加的字段是:

private final Map<String, String> extraProperties = new HashMap<String, String>(); 

这要么从此类中删除,要么更改为 private final transient 字段。

附言。不用告诉我,自定义序列化代码应该可能被添加,然后整个事情应该可能被重构,以将持久性和 transient 数据分离到不同的类.. .

最佳答案

删除(或临时化)这些您不想序列化的冗余字段。然后尝试反序列化加载旧版本,其中存在现已删除的非 transient 字段。这当然会导致错误,因为类 serialVersionUID 现在不同了。然而,旧的和新的 serialVersionUID 都应该包含在消息中。

现在只需在您的类中定义 private static long serialVersionUID =,将其设置为旧值。文件中有多余字段的类内容将被加载,这些多余字段的值将被忽略。

但是您现在遇到了另一个问题:您可能已经保存了两种不同类型的文件:旧版本和新版本。它们将具有不同的 serialVersionUID,因此我们可以加载其中一个,但不能同时加载两者。 serialVersionUID 是最终的,但也许您仍然可以设置和探测不同的值作为 described here .

从序列化的角度来看,将字段更改为 transient 与删除字段是一样的。它不会被存储,也不会被加载。但是,如果 serialVersionUID 未固定,则将先前的非 transient 字段声明为 transient 将更改它。

如果逐项,如果 serialVersionUID 现在是硬编码并且与文件中的 serialVersionUID 相匹配,那么您的问题的答案是:

  1. 没有。
  2. 没有。
  3. 没有。

作为“无”我的意思是类被反序列化而没有为 transient 字段赋值(如果存在)并且没有错误报告。

如果 serialVersionUID 不匹配,则抛出异常,即使类的其余部分匹配也是如此。

关于Java反序列化,将字段更改为 transient ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14274245/

相关文章:

Java序列化到文件

c# - 将 "/Date(1309498021672)/"反序列化为 DateTime

Java:这种方法线程安全吗?

java - 初始化的java数组是进入栈还是堆?

java - 将 Set<Map.Entry<K, V>> 转换为 HashMap<K, V>

c# - 使用 Json.net - C# 对象的部分自定义序列化

使用 Boost 对复杂数据进行 C++ 序列化

java - HL7 - 指定的患者位置

java - 重构 JPA 的 toPredicate 方法以支持 Java 7 和 8

c# - 如何将 DateTime 从 JSON 转换为 C#?