Hibernate查询PostgreSQL JSON结果映射DTO报JDBC type 1111错误如何解决
错误原因说明
报错org.hibernate.MappingException: No Dialect mapping for JDBC type: 1111是因为PostgreSQL返回的json_agg结果是JSON类型,对应JDBC的未定义类型1111,默认Hibernate没有配置该类型到Java集合的映射规则。
注意:尽量不要使用
System作为自定义类/接口名,会和JDK内置的java.lang.System冲突,容易引发编译或运行异常,建议改为自定义名称如SystemDTO。
解决方案
方案1:SQL层面转字符串+接口投影默认方法反序列化(最简单,无需额外配置)
首先修改原生SQL,将json结果转为text字符串:
@Query(value = "SELECT category, " + " json_agg(json_build_object('id', id, 'name', name))::text as role " + "FROM table " + "GROUP BY category;", nativeQuery = true) Collection<SystemProjection> getSystem();
调整投影接口,增加默认方法做JSON反序列化,引入Jackson的ObjectMapper即可:
import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import java.util.List; public interface SystemProjection { String getCategory(); String getRole(); // 先接收字符串类型的JSON // 默认方法反序列化为Role集合 default List<Role> getRoleList() { ObjectMapper objectMapper = new ObjectMapper(); try { return objectMapper.readValue(getRole(), new TypeReference<List<Role>>() {}); } catch (Exception e) { throw new RuntimeException("JSON反序列化失败", e); } } interface Role { Long getId(); String getName(); } }
调用的时候直接用getRoleList()方法就能拿到转换后的Role集合。
方案2:注册JSON类型到Hibernate方言(适合全局统一处理)
如果项目中大量用到PostgreSQL的JSON类型,可以自定义方言注册JSON映射:
- 自定义PostgreSQL方言类:
import org.hibernate.dialect.PostgreSQLDialect; public class CustomPostgreSQLDialect extends PostgreSQLDialect { public CustomPostgreSQLDialect() { super(); // 注册JDBC Type 1111对应JSON类型映射 this.registerColumnType(java.sql.Types.OTHER, "json"); this.registerColumnType(java.sql.Types.OTHER, "jsonb"); } }
- 配置文件中指定使用自定义方言,以Spring Boot为例,在application.yml中配置:
spring: jpa: properties: hibernate: dialect: 你的包名.CustomPostgreSQLDialect
- 如果你用的是Hibernate 6+,可以直接在投影上用
@JdbcTypeCode(SqlTypes.JSON)注解标注role字段即可自动映射为List。
方案3:使用Tuple接收结果手动转换
如果不想修改方言也不想改SQL,可以直接用Tuple接收查询结果,再手动转换为DTO:
@Query(value = "SELECT category, " + " json_agg(json_build_object('id', id, 'name', name)) as role " + "FROM table " + "GROUP BY category;", nativeQuery = true) Collection<Tuple> getSystemRaw();
转换逻辑:
ObjectMapper objectMapper = new ObjectMapper(); List<SystemDTO> systemList = getSystemRaw().stream().map(tuple -> { SystemDTO dto = new SystemDTO(); dto.setCategory(tuple.get("category", String.class)); String roleJson = tuple.get("role").toString(); try { dto.setRole(objectMapper.readValue(roleJson, new TypeReference<List<RoleDTO>>() {})); } catch (Exception e) { throw new RuntimeException(e); } return dto; }).toList();
对应的DTO类定义:
import lombok.Data; import java.util.List; @Data public class SystemDTO { private String category; private List<RoleDTO> role; } @Data public class RoleDTO { private Long id; private String name; }
内容的提问来源于stack exchange,提问作者Дмитрий Велигор
相关产品推荐
相关产品推荐

