Redis反序列化錯誤
最近使用Redis做緩存,用着好好的,返現有一個方法的在從Redis獲取緩存時報錯,無法正常獲取到緩存,從報錯信息看,是不能發序列化。在這里記錄一下解決方法。
直接貼上錯誤:Could not read JSON: Cannot construct instance of java.util.ArrayList$SubList(no Creators, like default construct, exist): no default no-arguments constructor found
因為這個序列化的對象較為復雜,嵌套了多個List對象,由於看到錯誤信息中提示“no Creators,like default contract”等字樣,以為是缺少了無參構造函數,就加上lombok的@NoArgsConstructor注解,重新測試還是同樣的錯誤,其實@NoArgsConstructor不是必須加的,因為已經加了@AllArgsConstructor注解了。
於是又仔細看錯誤信息,“SubList”,罪魁禍首就是這個方法。我們的代碼中確實用到了Sublis方法對緩存對象中的ArrayList進行了截取。正因為使用了這個方法,導致緩存對象無法反序列化。
讓我們來看看Sublist的源碼:
subList方法返回的是一個List,這個List是一個interface,繼承自Collection, 而且Collection也是interface,一層層看過去,都是沒有實現Serializable接口的,所以不能序列化/反序列化。
看到這里大家應該明白了,ArrayList.subList方法返回的對象是一個sublist類型的視圖,這個sublist類型的是ArrayList的一個內部類,不支持序列化。視圖的含義就是它里面的元素數量變了,但是操作其中的元素實際上還是操作的原來的list,並不是新的那份list。如果改變原有的list,那么就會拋出ConcurrentModificationException異常。
根本原因找到了,就看看怎么解決吧。
解決方法也是挺簡單的,重新創建一個實現序列化的List,將截取后的list存入,從而實現可序列化。
// 原錯誤代碼 bannerList = bannerList.subList(0, SLIDING_SIZE); // 修改后的正確代碼 bannerList = new ArrayList<>(slidingBanner.subList(0, SLIDING_SIZE));
在使用Redis進行緩存對象時,對於被緩存的對象,由於JSON序列化工具Jackson的一些限制,必須使用lombok的@Data和@AllArgsConstructor來修飾,否者能出現緩存進了Redis但無法反序列化的問題。切記不能將被緩存對象聲明成final!
具體可參見參見https://github.com/FasterXML/jackson-docs/wiki/JacksonPolymorphicDeserialization
歡迎大家關注公眾號,一起走上Java實戰之路!!!
作者:怎么改
版權歸作者所有,轉載請注明出處,歡迎轉載