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

使用InheritanceType.JOINED策略时,Jsonb类型列获取错误

问题原因

Hibernate在处理带泛型参数的JOINED继承实体时,会因泛型擦除导致父实体的jsonb列类型映射被覆盖。由于JOINED策略下父实体的元数据是所有子类共享的,运行时泛型参数被擦除后,Hibernate无法区分不同子类对应的泛型类型。当同时存在B、C两个子类时,后加载的子类(比如C)会将父实体的jsonb列类型替换为自己的泛型参数类型(CAttribute),导致查询B实例时,Hibernate错误地用CAttribute反序列化jsonb列。

解决方案

方案1:移除父实体泛型,子类独立定义jsonb属性

将父实体A改为非泛型的抽象实体,让每个子类自行定义对应类型的jsonb属性,避免共享类型映射冲突:

修改后的父实体A:

@Entity
@Inheritance(strategy = InheritanceType.JOINED)
@DiscriminatorColumn(name = "entity_type", discriminatorType = DiscriminatorType.STRING)
public abstract class A extends AbstractDomainJsonEntity<AJsonContent, String> {

    @Id
    @GeneratedValue(generator = "uuid2")
    @GenericGenerator(name = "uuid2", strategy = "org.hibernate.id.UUIDGenerator")
    @NotNull(groups = OnUpdate.class)
    @Null(groups = OnCreate.class)
    @Column(name = "a_id", columnDefinition = "VARCHAR(255)")
    @JsonProperty("aId")
    @Schema(description = "This attribute indicates unique id of OriginationJsonApplication")
    private String id;

    private String aAttribute;

    // 定义抽象方法统一json内容的访问入口
    public abstract AJsonContent getJsonContent();
    public abstract void setJsonContent(AJsonContent content);
}

子类B:

@Entity
@DiscriminatorValue("B")
public class B extends A {

    private String bAttribute;

    @Column(columnDefinition = "jsonb")
    @JsonProperty("jsonContent")
    private BAttribute jsonContent;

    @Override
    public BAttribute getJsonContent() {
        return jsonContent;
    }

    @Override
    public void setJsonContent(AJsonContent content) {
        this.jsonContent = (BAttribute) content;
    }
}

子类C:

@Entity
@DiscriminatorValue("C")
public class C extends A {

    private String cAttribute;

    @Column(columnDefinition = "jsonb")
    @JsonProperty("jsonContent")
    private CAttribute jsonContent;

    @Override
    public CAttribute getJsonContent() {
        return jsonContent;
    }

    @Override
    public void setJsonContent(AJsonContent content) {
        this.jsonContent = (CAttribute) content;
    }
}

方案2:使用@Type注解为子类指定自定义json类型

如果希望保留父实体的泛型结构,可以为每个子类的jsonb列指定独立的Hibernate类型,通过自定义UserType来区分不同的泛型参数:

  1. 为BAttribute和CAttribute分别实现自定义的UserType,负责json的序列化和反序列化。
  2. 在子类中重写父实体的json属性,并用@Type注解指定对应的自定义类型:
@Entity
public class B extends A<BAttribute> {

    private String bAttribute;

    @Override
    @Type(type = "com.yourpackage.BAttributeJsonType")
    @Column(columnDefinition = "jsonb")
    public BAttribute getJsonContent() {
        return super.getJsonContent();
    }
}

同理,子类C指定对应的CAttributeJsonType,确保Hibernate为每个子类使用独立的类型解析逻辑。

关键注意点
  • 显式添加@DiscriminatorColumn和@DiscriminatorValue可以让Hibernate更清晰地区分子类类型,避免继承映射混淆。
  • 泛型擦除是Java的特性,ORM框架无法在运行时直接获取泛型参数的具体类型,因此依赖泛型来区分实体属性类型的方案在多子类场景下必然会出现冲突。

内容的提问来源于stack exchange,提问作者amit kumar

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 04:30:59