如何保证Java序列化中枚举的一致性?

2022-09-03 05:33:29

当我序列化对象时,我可以在类级别使用 serialVersionUID 机制来确保两种类型的兼容性。

但是,当我序列化枚举值的字段时会发生什么情况?有没有办法确保枚举类型在序列化和反序列化之间没有纵?

假设我有一个枚举,如 OperationResult {SUCCESS, FAIL},以及一个正在序列化的对象中名为“result”的字段。当对象被反序列化时,我如何确保即使有人恶意反转了这两个结果,结果仍然是正确的?(假设枚举在其他地方声明为静态枚举)

出于好奇,我想知道 - 我使用jar级身份验证来防止操纵。


答案 1

寄件人: http://www.theserverside.com/news/thread.tss?thread_id=50190#265205

枚举功能的设计者决定在运行时创建新的枚举对象没有用例。他们非常小心地不允许它。

因此,枚举对象看起来无法完整地序列化和反序列化。另外,从 http://java.sun.com/javase/6/docs/platform/serialization/spec/serial-arch.html#6469

枚举常量的序列化方式与普通可序列化或可外部化对象的序列化方式不同。枚举常量的序列化形式仅由其名称组成;常量的字段值不存在于窗体中。为了序列化枚举常量,ObjectOutputStream 将写入枚举常量的 name 方法返回的值。为了反序列化枚举常量,ObjectInputStream从流中读取常量名称;然后通过调用 java.lang.Enum.valueOf 方法获取反序列化的常量,并将常量的枚举类型与接收的常量名称一起作为参数传递。与其他可序列化或可外部化的对象一样,枚举常量可以用作随后出现在序列化流中的反向引用的目标。

无法自定义枚举常量序列化的过程:在序列化和反序列化过程中,将忽略枚举类型定义的任何特定于类的 writeObject、readObject、readObjectNoData、writeReplace 和 readResolve 方法。类似地,任何串行持久性字段或串行VersionUID字段声明也会被忽略 - 所有枚举类型都有一个固定的串行VersionUID为0L。记录枚举类型的可序列化字段和数据是不必要的,因为发送的数据类型没有变化。


答案 2

枚举在反序列化期间被读取替换。引用版本 1.5 的序列化发行说明

序列化枚举实例的规则与序列化“普通”可序列化对象的规则不同:枚举实例的序列化形式仅由其枚举常量名称以及标识其基本枚举类型的信息组成。反序列化行为也有所不同 - 类信息用于查找适当的枚举类,并且使用该类和接收的常量名称调用 Enum.valueOf 方法,以便获取要返回的枚举常量。