Spring Boot JPA原生查询JSONB自动映射DTO的实现方法
问题描述
依赖配置:
springBootVersion = '3.4.5' org.springframework.boot:spring-boot-starter-data-jpa io.hypersistence:hypersistence-utils-hibernate-63:3.9.0
实体类中通过以下配置实现jsonb列到List<SomeDtoClass>的自动转换:
@Entity class TestEntity { // ... @Type(JsonBinaryType.class) @Column(columnDefinition = "jsonb") List<SomeDtoClass> test; }
但使用原生SQL查询返回自定义DTO时,无法自动转换jsonb字段,报错Cannot cast java.lang.String to java.util.List:
@Repository interface Repo extends JpaRepository<TestEntity, UUID> { @Query( """ SELECT CAST(test AS jsonb) AS test, 'example' AS example FROM test """, nativeQuery = true ) List<Dto> find(); }
目标DTO定义:
@Data @NoArgsConstructor @AllArgsConstructor class Dto { List<SomeDtoClass> test; String example; }
需要实现DTO字段的自动类型转换,复用实体类中的转换逻辑,且不新增额外依赖。
解决方案
方法一:使用@SqlResultSetMapping指定类型映射
- 定义结果集映射,为
test列指定JsonBinaryType类型转换器:
@SqlResultSetMapping( name = "DtoMapping", classes = @ConstructorResult( targetClass = Dto.class, columns = { @ColumnResult(name = "test", type = JsonBinaryType.class), @ColumnResult(name = "example", type = String.class) } ) ) // 可将此注解添加到TestEntity类上,或单独创建一个空的实体类承载映射配置 @Entity class DummyMappingHolder {}
- 在原生查询中引用该结果集映射:
@Repository interface Repo extends JpaRepository<TestEntity, UUID> { @Query( value = """ SELECT test AS test, 'example' AS example FROM test """, nativeQuery = true, resultSetMapping = "DtoMapping" ) List<Dto> find(); }
方法二:在DTO字段上添加@Type注解
直接在DTO的test字段上添加实体类中相同的@Type注解:
@Data @NoArgsConstructor @AllArgsConstructor class Dto { @Type(JsonBinaryType.class) List<SomeDtoClass> test; String example; }
同时确保DTO所在包被Hibernate扫描到,可在application.properties中添加配置:
spring.jpa.properties.hibernate.archive.autodetection=class, hbm
说明
- 方法一更可靠,原生查询的结果集映射明确指定了类型转换规则,不受DTO扫描范围影响。
- 两种方法均复用已有的
JsonBinaryType转换器,无需新增依赖。
内容的提问来源于stack exchange,提问作者Marat Tim
相关产品推荐
相关产品推荐

