在Java中序列化枚举是否有很好的替代方案?

时间:2016-08-01 13:34:16

标签: java serialization enums

Java语言从添加枚举中获益匪浅;但遗憾的是,在具有不同代码级别的系统之间发送序列化对象时,它们无法正常工作。

示例:假设您有两个系统A和B.它们都以相同的代码级别开始,但在某些时候开始在不同的时间点看到代码更新。现在假设有一些

public enum Whatever { FIRST; }

还有其他对象可以引用该枚举的常量。这些对象被序列化并从A发送到B,反之亦然。现在考虑B有更新版本的Whatever

public enum Whatever { FIRST; SECOND }

然后:

class SomethingElse implements Serializable { ...
  private final Whatever theWhatever;
  SomethingElse(Whatever theWhatever) {
    this.theWhatever = theWhatever; ..

获得实例化......

SomethingElse somethin = new SomethingElse(Whatever.SECOND)

然后序列化并发送到A(例如,作为一些RMI调用的结果)。这很糟糕,因为现在反序列化过程中会出现错误A:A知道任何枚举类,但是在没有SECOND的版本中。

我们认为这很艰难;现在我非常渴望将枚举用于实际上“完美用于枚举”的情况;仅仅因为我知道我以后不能轻易扩展现有的枚举。

现在我想知道:是否有(好的)策略来避免与枚举的兼容性问题?或者我真的要回到“pre-enum”时代;并且不要使用枚举,但必须依赖于我在整个地方使用普通字符串的解决方案?

更新:请注意,使用 serialversionuid 根本没有帮助。那件事只能帮助你使一个不相容的变化“更明显”。但重点是:我不关心为什么反序列化失败 - 因为我必须避免它发生。而且我也无法改变序列化对象的方式。我们正在做RMI;我们正在序列化为二进制;我没办法改变它。

2 个答案:

答案 0 :(得分:6)

正如@Jesper在评论中提到的,我会为你的服务间通信推荐类似JSON的东西。这样您就可以更好地控制未知Enum值的处理方式。

例如,使用始终很棒的Jackson,您可以使用Deserialization Features READ_UNKNOWN_ENUM_VALUES_AS_NULLREAD_UNKNOWN_ENUM_VALUES_USING_DEFAULT_VALUE。两者都允许您的应用程序逻辑按您认为合适的方式处理未知的枚举值。

示例(直接来自Jackson doc)

enum MyEnum { A, B, @JsonEnumDefaultValue UNKNOWN }
...
final ObjectMapper mapper = new ObjectMapper();
mapper.enable(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_USING_DEFAULT_VALUE);

MyEnum value = mapper.readValue("\"foo\"", MyEnum.class);
assertSame(MyEnum.UNKNOWN, value);

答案 1 :(得分:0)

在针对不同的解决方案来回反复之后,我根据@GuiSim的建议找到了一个解决方案:可以构建一个包含枚举值的类。这个班可以

  1. 进行自定义反序列化;因此,我可以防止在反序列化过程中不会出现异常
  2. 提供简单的方法,如 isValid() getEnumValue():第一个方法告诉你枚举反序列化是否真正起作用;第二个返回反序列化的枚举(或抛出异常)