Hibernate 6.4原生查询如何将JSONB转换为ArrayList?
Hibernate 6.4 兼容6.1 jsonb自动转为ArrayList的解决方案
问题背景
在PostgreSQL环境下,以下Hibernate代码在6.1和6.4版本表现存在差异:
var rows = session .createNativeQuery("SELECT CAST('[1,2,3]' as jsonb) as data, 2 as id", Object[].class) .addScalar("data") .addScalar("id", StandardBasicTypes.INTEGER) .list(); rows.forEach(row -> System.out.println(row[0].getClass() + " -> " + row[0]));
- Hibernate 6.1输出:
class java.util.ArrayList -> [1, 2, 3]
- Hibernate 6.4输出:
class java.lang.String -> [1, 2, 3]
6.1版本会自动将jsonb数组转换为ArrayList,但6.4版本仅将该字段读取为String类型,尝试多种StandardBasicTypes均无法复现6.1的行为,需解决在6.4中实现相同转换效果的问题。
解决方案
方法1:显式指定JsonType映射
Hibernate 6.4中需要明确指定jsonb字段的类型为JsonType,并指定目标转换类型为List:
import org.hibernate.type.JsonType; var rows = session .createNativeQuery("SELECT CAST('[1,2,3]' as jsonb) as data, 2 as id", Object[].class) .addScalar("data", JsonType.of(List.class)) .addScalar("id", StandardBasicTypes.INTEGER) .list();
此方式可直接将jsonb数组转为ArrayList,与6.1版本行为一致。
方法2:自定义全局类型转换器
若需全局统一处理jsonb到List的转换,可自定义属性转换器:
- 实现
AttributeConverter:
import jakarta.persistence.AttributeConverter; import jakarta.persistence.Converter; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import java.util.List; @Converter(autoApply = true) public class JsonbToListConverter implements AttributeConverter<List<Object>, String> { private static final ObjectMapper objectMapper = new ObjectMapper(); @Override public String convertToDatabaseColumn(List<Object> attribute) { try { return objectMapper.writeValueAsString(attribute); } catch (Exception e) { throw new RuntimeException("转换List为JSON字符串失败", e); } } @Override public List<Object> convertToEntityAttribute(String dbData) { try { return objectMapper.readValue(dbData, new TypeReference<List<Object>>() {}); } catch (Exception e) { throw new RuntimeException("转换JSON字符串为List失败", e); } } }
- 查询中指定使用该转换器对应的自定义类型:
import org.hibernate.type.CustomType; var rows = session .createNativeQuery("SELECT CAST('[1,2,3]' as jsonb) as data, 2 as id", Object[].class) .addScalar("data", new CustomType(new JsonbToListConverter())) .addScalar("id", StandardBasicTypes.INTEGER) .list();
方法3:使用DTO映射(推荐)
定义与查询结果匹配的DTO类:
public class ResultDto { private List<Object> data; private Integer id; public ResultDto(List<Object> data, Integer id) { this.data = data; this.id = id; } // getter方法 public List<Object> getData() { return data; } public Integer getId() { return id; } }
将DTO作为查询返回类型,Hibernate会自动完成jsonb到List的映射:
var rows = session .createNativeQuery("SELECT CAST('[1,2,3]' as jsonb) as data, 2 as id", ResultDto.class) .list(); rows.forEach(dto -> System.out.println(dto.getData().getClass() + " -> " + dto.getData()));
内容的提问来源于stack exchange,提问作者Chad
相关产品推荐
相关产品推荐

