Xsank's Blog

java自带序列化注意点

开题

大家都知道java使用自带的序列化的时候对象需要实现Serializable接口,然后根据你业务需求,决定是否要自定义readObjectwriteObject,其中其实会有一个类属性serialVersionUID,你可以不写,序列化后系统会给你生成好,在反序列化的时候比对校验,都建议说最好给每个序列化类配上一个固定的,那么如果没配呢?

解读

事实上如果你定了一个协议,八百年不动的话其实没写那个id也没什么,但是如果你动了问题就来了。
通常你作为序列化端,可能某种情况需要升级,照常理说对端也要升级,但是奇葩的情况是在协议里面它居然有方法,只是稍微改了改,属性是完全没动的,即便如此,在只有一端升级的情况下是会报错的:

1
2
3
4
java.io.InvalidClassException: org.test.hehe.Condition;
local class incompatible: stream classdesc serialVersionUID = -8099535478841222210,
local class serialVersionUID = -800932720215515472
at

更蛋疼的是如果这个方法还必须添加,服务端不能升级,那个协议里面还嵌套了一些协议。。。

好吧,那唯一的解法就是恢复到旧版协议,然后打出序列化协议的id,可以使用如下方法:

1
2
3
public static long showSUID(Object obj) {
return ObjectStreamClass.lookup(obj.getClass()).getSerialVersionUID();
}

之后将这些id赋值给新的协议,以后就用这个了。。。

总结

  1. 协议里面要只包含属性,不要包含方法实现
  2. 协议的serialVersionUID一定要配置