1. 程式人生 > >由Java反序列化物件異常想到的

由Java反序列化物件異常想到的

今天寫程式碼時候遇到一個異常,異常資訊如下:


Caused by: java.lang.RuntimeException: java.util.concurrent.ExecutionException: org.springframework.data.redis.serializer.SerializationException: Cannot deserialize; nested exception is org.springframework.core.serializer.support.SerializationFailedException: Failed to deserialize payload. Is the byte array a result of corresponding serialization for DefaultDeserializer?; nested exception is java.io.InvalidClassException: com.netease.kaola.generic.act.dto.module.ModuleGoodsDTO; local class incompatible: stream classdesc serialVersionUID = -526324944915280489, local class serialVersionUID = 4094977077022888368


Caused by: org.springframework.core.serializer.support.SerializationFailedException: Failed to deserialize payload. Is the byte array a result of corresponding serialization for DefaultDeserializer?; nested exception is java.io.InvalidClassException: com.netease.kaola.generic.act.dto.module.ModuleGoodsDTO; local class incompatible: stream classdesc serialVersionUID = -526324944915280489, local class serialVersionUID = 4094977077022888368


Cannot deserialize,很明顯,反序列化異常。特別注意這一句:redis.serializer.SerializationException: Cannot deserialize,用了Redis儲存物件列表,取物件列表時候反序列化出錯了。在程式碼裡有這一行 Map<Long, List<ModuleGoods>> moduleIdGoodsListMap = (Map<Long, List<ModuleGoods>>) redisClient.get(RedisKeyConstant.GOODS_INFO_LIST+currentModuleInfo.getId()); 這裡stream classdesc serialVersionUID = -526324944915280489,local class serialVersionUID = 4094977077022888368,兩個serialVersionUID不一致,反序列化異常。


回想了一下,我給ModuleGoods類新增加了1個欄位categoryId,但是ModuleGoods類前面加了 @SuppressWarnings("serial"),沒有註明 serialVersionUID,這樣新增(修改或刪除)了欄位,local class serialVersionUID 預設是會自動變化的。


才想起來serialVersionUID的作用:


序列化時為了保持版本的相容性,即在版本升級時反序列化仍保持物件的唯一性。
有兩種生成方式:
       一個是預設的1L,比如:private static final long serialVersionUID = 1L;
       一個是根據類名、介面名、成員方法及屬性等來生成一個64位的雜湊欄位,比如:
       private static final   long     serialVersionUID = xxxxL;


當你一個類實現了Serializable介面,如果沒有定義serialVersionUID,Eclipse會提供黃色警告,如果沒有考慮到相容性問題時,不管或者簡單的加一個 @SuppressWarnings("serial") 註解,就會出現上述問題。


如果你的類Serialized序列化存到硬碟上面後,可是後來你卻更改了類的field(增加或減少或改名),當你Deserialize時,就會出現Exception的,這樣就會造成不相容性的問題。
但當serialVersionUID設定相同時,它就會將不一樣的field以type的預設值(屬性預設值)Deserialize,可避開不相容性問題。


這裡給類 ModuleGoodsDTO 加上 private static final long serialVersionUID = -526324944915280489L; 就好了。