You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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作为实例化目标。结合给出的自定义配置,最高概率的诱因有两个:

  1. 自定义KeyspaceConfiguration逻辑错误:当前hasSettingsFor方法对所有传入类型无差别返回true,并且会为所有不存在配置的类型动态生成KeyspaceSettings,包括Base接口本身。Spring Data Redis在解析属性时,只要发现对应类型存在Keyspace配置,就会将其判定为独立的根实体类型,直接走实体实例化逻辑,不会再读取嵌套属性上的_class字段做类型推导,尝试实例化接口自然报错。
  2. 自定义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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 13:45:31