根本原因是jackson反序列化时缺乏类型信息,只能退化为linkedhashmap;必须通过genericjackson2jsonredisserializer配合启用defaulttyping的objectmapper,或使用jackson2jsonredisserializer指定具体类型,才能正确还原实体类。

直接结论:不是序列化器选错了,而是反序列化时 Jackson 不知道该还原成哪个类——必须显式告诉它,否则默认就给你塞个 LinkedHashMap。
为什么取出来总是 LinkedHashMap 而不是你的实体类?
这是最典型的表象错误。根本原因在于 Jackson2JsonRedisSerializer(或 GenericJackson2JsonRedisSerializer)在反序列化 JSON 字符串时,没拿到类型信息,只能退化为通用容器。它不“猜”你存的是 User 还是 Order,除非你提前注册好。
- 用
new Jackson2JsonRedisSerializer(Object.class)初始化,等于把反序列化入口设成了最宽泛的Object,Jackson 只能按 JSON 结构映射成LinkedHashMap - 如果存的是
Map类型(比如HashMap),取出来变成LinkedHashMap是正常行为——因为 Jackson 默认只保证接口语义,不保留具体实现类 - 真正要报
ClassCastException,往往是业务代码写了(User) redisTemplate.opsForValue().get("key"),而实际返回的是LinkedHashMap
Jackson2JsonRedisSerializer 和 GenericJackson2JsonRedisSerializer 怎么选?
别被名字误导:GenericJackson2JsonRedisSerializer 才是带类型提示能力的那个;Jackson2JsonRedisSerializer 是“纯 JSON”模式,不写 @class 字段,也不读类型信息。
-
Jackson2JsonRedisSerializer<t></t>:适合存固定类型,比如只存User,就初始化为new Jackson2JsonRedisSerializer(User.class);但不能混存多种类型 -
GenericJackson2JsonRedisSerializer:支持多态,会自动在 JSON 里加@class字段(如{"@class":"com.example.User","name":"zhang"}),但必须配好ObjectMapper白名单,否则抛InvalidTypeIdException - Spring Boot 2.6+ 默认禁用
DEFAULT_TYPING,老项目升级后,原来能跑的GenericJackson2JsonRedisSerializer会突然报错
怎么配一个安全又可用的 ObjectMapper?
核心就两条:关掉危险的全局白名单,只注册你真正在用的类或包。
- 不要用
mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL)—— 这等价于开ALLOW_ALL,有反序列化 RCE 风险 - 推荐注册整个包:
mapper.registerSubtypes(PackageVersion.create("com.example.dto", null)),再配合mapper.activateDefaultTyping(..., JsonTypeInfo.As.PROPERTY, JsonTypeInfo.Id.CLASS) - 如果只用几个类,更安全:
mapper.registerSubtypes(new NamedType(User.class, "User"), new NamedType(Order.class, "Order")) - Lombok 实体类必须有
@NoArgsConstructor,否则 Jackson 构造失败也会表现为类型转换异常
为什么改了 RedisTemplate 还是报错?
常见疏漏点:你可能只改了 RedisTemplate<string object></string>,但业务里实际用的是 StringRedisTemplate 或缓存注解(@Cacheable)背后的默认模板。
-
StringRedisTemplate是独立 Bean,它的 value 序列化器默认是StringRedisSerializer,不走你配的GenericJackson2JsonRedisSerializer,存对象会直接失败 -
@Cacheable默认使用cacheManager绑定的RedisCacheConfiguration,需单独配置RedisCacheConfiguration.serializeValuesWith(...) - 确认生效方式:打个断点进
GenericJackson2JsonRedisSerializer.deserialize(),看是否真被调用;或者用redis-cli --raw get key看 Redis 里存的到底是不是带@class的 JSON
最易被忽略的一点:类型信息只在序列化时写入、反序列化时读取。如果你的 key 是手动用 redis-cli set 写进去的纯 JSON(没 @class),哪怕配得再完美,反序列化也必然失败——Jackson 没法无中生有猜类型。











