Spring Data Redis Repository多态属性反序列化报错排查
Spring Data Redis查询时忽略
_class字段尝试实例化接口类型异常 问题描述
相关代码定义如下:
@Getter @Setter @RedisHash class Root { private Base base; } public interface Base { } @Getter @Setter public class Implementor implements Base { // 业务字段省略 } public class CustomKeyspaceConfiguration extends KeyspaceConfiguration { private final String prefix; public SagtKeyspaceConfiguration(String prefix) { super(); this.prefix = prefix; } @Override public boolean hasSettingsFor(Class<?> type) { if (super.hasSettingsFor(type) == false) { KeyspaceSettings settings = new KeyspaceSettings(type, prefix + ClassUtils.getUserClass(type).getName()); addKeyspaceSettings(settings); } return true; } }
- 为
Root类绑定CrudRepository后,对象可以正常写入Redis - 调用
findById查询已存储对象时抛出异常:
Failed to instantiate some.package.name.Base using constructor NO_CONSTRUCTOR with arguments
- 检查Redis中存储的Hash结构,嵌套属性的类型标识字段已正确写入:
base._class: some.package.name.Implementor
- 使用完全相同版本的
spring-data-redis 2.6.4搭建最小验证工程时,相同代码可以正常运行,说明项目中存在自定义配置干扰了默认逻辑。
问题根因
这个异常的核心触发点是框架在反序列化base字段时,没有读取Hash中存储的_class类型信息,直接使用字段声明的接口类型Base作为实例化目标。结合给出的自定义配置,最高概率的诱因有两个:
- 自定义
KeyspaceConfiguration逻辑错误:当前hasSettingsFor方法对所有传入类型无差别返回true,并且会为所有不存在配置的类型动态生成KeyspaceSettings,包括Base接口本身。Spring Data Redis在解析属性时,只要发现对应类型存在Keyspace配置,就会将其判定为独立的根实体类型,直接走实体实例化逻辑,不会再读取嵌套属性上的_class字段做类型推导,尝试实例化接口自然报错。 - 自定义Redis序列化器配置问题:如果项目中自定义了
Jackson2JsonRedisSerializer或者GenericJackson2JsonRedisSerializer,关闭了默认类型推导、修改了类型字段名、或者配置了固定的目标类型,也会导致序列化器读不到_class字段,直接用字段声明的接口类型反序列化。
修复方案
- 首先修正
CustomKeyspaceConfiguration的判断逻辑,不要为接口、抽象类等非实体类型生成Keyspace配置:
@Override public boolean hasSettingsFor(Class<?> type) { // 跳过接口、抽象类,仅为具体实体类生成keyspace配置 if (type.isInterface() || Modifier.isAbstract(type.getModifiers())) { return super.hasSettingsFor(type); } if (!super.hasSettingsFor(type)) { KeyspaceSettings settings = new KeyspaceSettings(type, prefix + ClassUtils.getUserClass(type).getName()); addKeyspaceSettings(settings); } return super.hasSettingsFor(type); }
- 检查Redis序列化相关配置:如果自定义了Jackson序列化器,确认开启了默认多态类型处理,且类型标识字段名和Redis中存储的
_class一致,不要为嵌套属性固定绑定Base类型作为反序列化目标。 - 排查项目中是否存在自定义
RedisCustomConversions、RedisMappingContext的Bean,如果注册了Base类型相关的自定义转换器、类型别名,也会覆盖默认的多态解析逻辑,需要同步调整。
内容的提问来源于stack exchange,提问作者Guerric P
相关产品推荐
相关产品推荐

