根本原因是jackson反序列化时类型匹配失败:未配置白名单或objectmapper导致invalidtypeidexception,或错误强转引发classcastexception;需用genericjackson2jsonredisserializer配合注册子类型的安全objectmapper。

Redis反序列化时报ClassCastException或InvalidTypeIdException
根本原因不是Redis本身出错,而是Jackson在反序列化时无法将JSON字符串还原成预期的Java类型。默认情况下,Jackson 2.10+ 启用了严格的类型检查(DEFAULT_TYPING被禁用),若序列化时写了类型信息(如@class字段),而反序列化时没开白名单或没配好ObjectMapper,就会抛InvalidTypeIdException;如果靠类型推断硬转(比如把JSON当LinkedHashMap读再强转),就容易触发ClassCastException。
- 典型错误信息:
com.fasterxml.jackson.databind.exc.InvalidTypeIdException: Could not resolve type id 'xxx' as a subtype of ... - 常见于用
StringRedisTemplate存对象但没配GenericJackson2JsonRedisSerializer,或自定义ObjectMapper时漏掉activateDefaultTyping或白名单注册 - Spring Boot 2.6+ 默认禁用
DEFAULT_TYPING,老项目升级后极易踩坑
如何给Jackson配置安全的反序列化白名单
不推荐全局开ALLOW_ALL(有反序列化RCE风险),应按需注册可信类或包。核心是配置ObjectMapper并传给GenericJackson2JsonRedisSerializer。
Redis 8.2.3 是一款安全优先的高性能键值存储系统。该版本紧急修复了可能引发远程代码执行(RCE)的高危漏洞(CVE-2025-62507),并解决了 HyperLogLog 及 Cuckoo Filter 等数据结构在特定场景下的崩溃问题。建议所有用户立即升级,以保障生产环境的系统稳定与数据安全。
- 注册具体类:
mapper.registerSubtypes(new NamedType(User.class, "User")) - 注册整个包(较常用):
mapper.registerSubtypes(PackageVersion.create("com.example.model", null)),再配合mapper.activateDefaultTyping(..., JsonTypeInfo.As.PROPERTY, JsonTypeInfo.Id.CLASS) - 更安全的做法是用
SimpleModule+SimpleAbstractTypeResolver限定反序列化目标类,例如只允许com.example.dto.*下的类 - 若用Lombok,确保实体类有无参构造器和
@NoArgsConstructor,否则Jackson构造失败也会伪装成类型转换异常
Spring Boot中配置RedisTemplate使用带白名单的Jackson
别直接改StringRedisTemplate——它只处理String。必须显式声明RedisTemplate<string object></string>并指定序列化器。
- 定义
ObjectMapperBean时启用白名单:@Bean public ObjectMapper objectMapper() { ObjectMapper mapper = new ObjectMapper(); mapper.activateDefaultTyping( mapper.getPolymorphicTypeValidator(), DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY ); mapper.registerModules(new SimpleModule().addAbstractTypeMapping( Serializable.class, HashMap.class )); return mapper; } - 配套声明
RedisTemplate:@Bean public RedisTemplate<string object> redisTemplate(RedisConnectionFactory factory, ObjectMapper mapper) { RedisTemplate<string object> template = new RedisTemplate(); template.setConnectionFactory(factory); template.setValueSerializer(new GenericJackson2JsonRedisSerializer(mapper)); template.setKeySerializer(new StringRedisSerializer()); template.afterPropertiesSet(); return template; }</string></string> - 注意:
GenericJackson2JsonRedisSerializer构造函数传ObjectMapper才会生效;只传byte[]或空参会回退到默认不安全配置
为什么加了白名单还报错?几个隐蔽点
白名单配了≠万事大吉,实际运行中常因版本、缓存残留、泛型擦除导致失败。
- Redis里存的老数据是旧版序列化格式(比如用
JdkSerializationRedisSerializer存的),新服务用Jackson读会直接IOException,不是类型异常,但日志容易误判 - 泛型类型信息丢失:存
List<user></user>时,Jackson默认只记ArrayList,不记元素类型;取出来强转(List<user>) obj</user>必然ClassCastException;解决办法是用TypeReference:redisTemplate.opsForValue().get(key, new TypeReference<list>>() {})</list> - Spring Boot 3.x 起
GenericJackson2JsonRedisSerializer已标记为@Deprecated,建议迁移到Jackson2JsonRedisSerializer并手动设ObjectMapper - 微服务间共享DTO时,务必保证类全限定名、字段名、getter/setter完全一致,一个字段加
@JsonIgnore都可能导致反序列化中途终止,后续字段全为null,再强转就崩
ClassCastException换个姿势出现。










