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

Spring Boot+PostgreSQL JSON字段自定义投影映射失败

问题原因

在JPQL投影查询中,Hibernate未自动应用实体字段上@Type(JsonType.class)的类型转换逻辑,导致查询返回的config字段是原始JDBC JSON对象(如PostgreSQL的PGobject),而非映射后的Config类型,与FooProjection的构造器参数类型不匹配,触发实例化错误。

解决方案

方案1:添加兼容Object类型的构造器

修改FooProjection,新增一个接受Long和Object类型参数的构造器,手动将JDBC JSON对象转换为Config类型:

@Getter
@Builder
@RequiredArgsConstructor
public class FooProjection {

  private final Long id;
  private final Config config;

  // 新增构造器,处理JDBC返回的JSON对象
  public FooProjection(Long id, Object configObj) {
    this.id = id;
    if (configObj instanceof PGobject pgObj) {
      try {
        this.config = new ObjectMapper().readValue(pgObj.getValue(), Config.class);
      } catch (Exception e) {
        throw new RuntimeException("Failed to parse Config from JSON", e);
      }
    } else {
      // 兼容已转换为Config类型的情况
      this.config = (Config) configObj;
    }
  }
}

需导入PostgreSQL驱动的org.postgresql.util.PGobject类,确保项目依赖PostgreSQL JDBC驱动。

方案2:改用JPA AttributeConverter替代Hibernate JsonType

用JPA标准的@Convert替换实体上的@Type(JsonType.class),让Hibernate在JPQL查询中自动处理类型转换:

  1. 创建自定义转换器:
import jakarta.persistence.AttributeConverter;
import jakarta.persistence.Converter;
import com.fasterxml.jackson.databind.ObjectMapper;

@Converter(autoApply = true)
public class ConfigConverter implements AttributeConverter<Config, String> {

  private final ObjectMapper objectMapper = new ObjectMapper();

  @Override
  public String convertToDatabaseColumn(Config config) {
    try {
      return objectMapper.writeValueAsString(config);
    } catch (Exception e) {
      throw new RuntimeException("Failed to serialize Config to JSON", e);
    }
  }

  @Override
  public Config convertToEntityAttribute(String dbJson) {
    try {
      return dbJson == null ? null : objectMapper.readValue(dbJson, Config.class);
    } catch (Exception e) {
      throw new RuntimeException("Failed to deserialize JSON to Config", e);
    }
  }
}
  1. 修改Foo实体的config字段:
// 替换原有的@Type(JsonType.class)
@Convert(converter = ConfigConverter.class)
private Config config;

修改后无需调整原查询语句,JPQL会自动将数据库JSON字符串转换为Config对象,正常实例化FooProjection。

方案3:在JPQL中显式转换类型

在查询语句中使用CAST显式指定类型转换,需确保Hibernate已注册Config对应的JSON类型:

@Query(
  """
    SELECT new path.to.package.FooProjection(
      f.id,
      CAST(f.config AS path.to.package.Config)
    )
    FROM Foo f
    WHERE ...
  """)
Optional<FooProjection> fetchMinimalFoo(Long fooId);

若使用vladmihalcea的JsonType,需在Hibernate配置中注册该类型为可转换的自定义类型。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 09:34:51