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

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数组,再输出为正确的数组结构。

额外检查

  1. 确认PostgreSQL查询结果:执行SELECT p.id, JSON_AGG(JSON_BUILD_OBJECT('id', pp.id)) AS photo_files语句,查看photo_files列返回的是原生JSON数组(如[{"id":1},{"id":2}]),而非字符串类型。
  2. 若使用Spring Data JPA,确保投影类的字段映射正确,没有额外的类型转换破坏JSON结构。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 21:52:38