Spring投影中如何读取PostgreSQL返回的JSON数组
问题解决:PostgreSQL JSON_AGG 投影序列化不符合预期
问题原因
你当前的实现中,PostgreSQL的JSON_AGG返回的是JSON数组类型,但投影类用String接收时,JPA会将其转义为带双引号的字符串(比如"[{\"id\":1}]")。自定义序列化器直接用writeRawValue输出这个字符串,导致最终返回的photoFiles是一个字符串值(或被错误包裹成数组元素),而非预期的JSON数组结构。
解决方案
下面提供两种可行的修复方式:
方案一:改用JsonNode接收JSON数据(推荐)
直接用Jackson的JsonNode类型接收数据库返回的JSON数组,无需自定义序列化器,Jackson会自动处理正确的序列化:
import com.fasterxml.jackson.databind.JsonNode import com.fasterxml.jackson.annotation.JsonProperty interface ItemProjection { fun getId(): Long @JsonProperty("photoFiles") fun getPhoto_files(): JsonNode }
- 此方式依赖Spring Data JPA对PostgreSQL JSON类型的自动转换,通常Spring Boot项目会自动配置好相关驱动和类型转换器。
方案二:修复自定义序列化器
如果必须保留String类型接收,需要在序列化器中先将转义后的字符串解析为JSON对象,再进行序列化:
import com.fasterxml.jackson.core.JsonGenerator import com.fasterxml.jackson.databind.JsonNode import com.fasterxml.jackson.databind.JsonSerializer import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.databind.SerializerProvider class PhotoFilesProjectionSerializer : JsonSerializer<String>() { private val objectMapper = ObjectMapper() override fun serialize(data: String?, gen: JsonGenerator, serializers: SerializerProvider) { if (!data.isNullOrEmpty()) { // 将字符串解析为JsonNode再序列化 val jsonNode: JsonNode = objectMapper.readTree(data) serializers.defaultSerializeValue(jsonNode, gen) } else { gen.writeStartArray() gen.writeEndArray() } } }
- 此方式会先把带转义的字符串(如
"[{\"id\":1}]")解析为真正的JSON数组,再输出为正确的数组结构。
额外检查
- 确认PostgreSQL查询结果:执行
SELECT p.id, JSON_AGG(JSON_BUILD_OBJECT('id', pp.id)) AS photo_files语句,查看photo_files列返回的是原生JSON数组(如[{"id":1},{"id":2}]),而非字符串类型。 - 若使用Spring Data JPA,确保投影类的字段映射正确,没有额外的类型转换破坏JSON结构。
内容的提问来源于stack exchange,提问作者Captain Jacky
相关产品推荐
相关产品推荐

