Gho*_*ica 7 java enums serialization
Java语言从添加枚举中获益匪浅; 但遗憾的是,在具有不同代码级别的系统之间发送序列化对象时,它们无法正常工作.
示例:假设您有两个系统A和B.它们都以相同的代码级别开始,但在某些时候开始在不同的时间点看到代码更新.现在假设有一些
public enum Whatever { FIRST; }
Run Code Online (Sandbox Code Playgroud)
还有其他对象可以引用该枚举的常量.这些对象被序列化并从A发送到B,反之亦然.现在考虑B有更新版本的Whatever
public enum Whatever { FIRST; SECOND }
Run Code Online (Sandbox Code Playgroud)
然后:
class SomethingElse implements Serializable { ...
private final Whatever theWhatever;
SomethingElse(Whatever theWhatever) {
this.theWhatever = theWhatever; ..
Run Code Online (Sandbox Code Playgroud)
获得实例化...
SomethingElse somethin = new SomethingElse(Whatever.SECOND)
Run Code Online (Sandbox Code Playgroud)
然后序列化并发送到A(例如,作为一些RMI调用的结果).这很糟糕,因为现在在A上反序列化时会出现错误:A知道Whatever枚举类,但是在没有SECOND的版本中.
我们认为这很艰难; 现在我非常渴望将枚举用于实际上"完美用于枚举"的情况; 仅仅因为我知道我以后不能轻易扩展现有的枚举.
现在我想知道:有没有(好)策略来避免与枚举的这种兼容性问题?或者我真的要回到"pre-enum"时代; 并且不要使用枚举,但必须依赖于我在整个地方使用普通字符串的解决方案?
更新:请注意,使用serialversionuid对此没有任何帮助.那件事只能帮助你使一个不相容的变化"更明显".但重点是:我不关心为什么反序列化失败 - 因为我必须避免它发生.而且我也无法改变序列化对象的方式.我们正在做RMI; 我们正在序列化为二进制; 我没办法改变它.
正如@Jesper在评论中提到的那样,我会为您的服务间通信推荐类似JSON的东西.这样您就可以更好地控制未知Enum值的处理方式.
例如,使用总是很棒的杰克逊你可以使用反序列化功能 READ_UNKNOWN_ENUM_VALUES_AS_NULL
或READ_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);
Run Code Online (Sandbox Code Playgroud)
在反复考虑不同的解决方案之后,我根据 @GuiSim 的建议找到了一个解决方案:可以构建一个包含枚举值的类。这堂课可以