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

将子类转换为PostgreSQL jsonb类型时遇Hibernate异常求助

解决方案

核心问题定位

异常IllegalStateException: Convert placed on Embedded attribute must define (sub)attributeName的根源是:你在@Embedded注解的字段上直接使用@Convert,但@Embedded用于将嵌入类的属性映射为数据库表的独立列,而你需要将整个嵌入类对象序列化为JSON存储到单个jsonb列,两者用法冲突。

分步修复

1. 修正实体类注解

移除content字段上的@Embedded注解,保留@Convert和@Column,确保整个SubClass对象被转换为JSON字符串存储到jsonb列,同时修复代码中的低级错误:

@Entity
@Table(name = "my_table")
public class MyClassEntity {

    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Column(name = "id", nullable = false)
    private UUID id;

    @Column(name = "description", nullable = false)
    private String description;

    @Convert(converter = SubClassConverter.class)
    @Column(name = "content", columnDefinition = "jsonb")
    private SubClass content;

    public void setId(UUID id) {
        this.id = id;
    }
    public UUID getId() {
        return this.id;
    }
    // 修正拼写错误:setDesctiption -> setDescription
    public void setDescription(String description) {
        this.description = description;
    }
    public String getDescription() {
        return this.description;
    }
    // 修正语法错误:补全参数括号
    public void setContent(SubClass content) {
        this.content = content;
    }
    public SubClass getContent() {
        return this.content;
    }
}

2. 修复转换器方法名错误

转换器类中convertToDatabaseColumn方法名拼写错误,修正为正确的方法名:

public class SubClassConverter implements AttributeConverter<SubClass, String>  {
   
    private ObjectMapper objectMapper = new ObjectMapper();

    public SubClassConverter() {
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    }

    @Override
    // 修正方法名:移除多余的SubClassConverter后缀
    public String convertToDatabaseColumn(SubClass in) {
        try {
            return objectMapper.writeValueAsString(in);
        }
        catch (Exception e) {
            throw new RuntimeException("Failed to convert SubClass to JSON", e);
        }
    }

    @Override
    public SubClass convertToEntityAttribute(String joined) {
        if (StringUtils.isEmpty(joined)) {
            return null;
        }
        try {
            return objectMapper.readValue(joined, SubClass.class);
        } catch (IOException e) {
            throw new RuntimeException("Failed to convert JSON to SubClass", e);
        }
    }
}

3. 优化仓库层实现

原生查询中不需要手动cast(:content as jsonb),转换器已将SubClass转为JSON字符串,PostgreSQL会自动识别并转换为jsonb类型。推荐直接使用CrudRepository的save方法,避免手写SQL的冗余:

@Repository
public interface MyClassRepository extends CrudRepository<MyClassEntity, UUID> {
    // 若坚持使用原生查询,修正参数类型为String(转换器输出类型)
    @Modifying
    @Transactional
    @Query(value = "insert into my_table (description, content) values (:description, :content)", nativeQuery = true)
    void insertMyClass(@Param("description") String description,
                       @Param("content") String content);
}

使用save方法时,直接调用myClassRepository.save(myClassEntity)即可,Hibernate会自动通过转换器处理content字段

可选方案:使用Hibernate原生JsonType(推荐)

若项目使用Hibernate 5.2+,可直接使用@Type注解指定JsonType,无需自定义转换器:

@Entity
@Table(name = "my_table")
public class MyClassEntity {
    // ...其他字段

    @Type(type = "jsonb")
    @Column(name = "content", columnDefinition = "jsonb")
    private SubClass content;

    // ...getter/setter
}

移除自定义的SubClassConverter后,Hibernate会自动通过Jackson完成对象与JSON的转换。

验证步骤

  1. 确认所有注解修正、语法错误修复完成
  2. 启动应用并测试写入操作,确认异常消失
  3. 查询数据库,验证content列存储的是正确的JSON格式数据

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 08:24:51