Redis反序列化错误Could not read JSON: Cannot construct instance of `java.util.ArrayList$SubList`

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
subList方法返回的是一个List,这个List是一个interface,继承自Collection, 而且Collection也是interface,一层层看过去,都是没有实现Serializable接口的,所以不能序列化/反序列化。

List
看到这里大家应该明白了,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实战之路!!!
Java实战之路
作者:怎么改
版权归作者所有,转载请注明出处,欢迎转载

猜你喜欢

转载自www.cnblogs.com/theonesmx/p/12498947.html