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

如何将深层JSON的sites.site映射为Site模型?Ktor序列化报错求助

解决Ktor序列化嵌套JSON的问题

问题根源

你直接尝试将整个API响应体反序列化为List<Site>,但API返回的是多层嵌套结构:根对象包含sites字段,sites又包含count和site数组。序列化器找不到顶层数组,所以抛出"Expected start of the array '['"错误。另外你的Site数据类最后一行多了个逗号,会导致编译失败,需要先修正这个语法问题。

方案一:创建匹配响应结构的顶层数据类(推荐新手)

定义完整的响应结构类,先反序列化整个响应,再提取需要的site数组,逻辑清晰易维护。

步骤1:修正Site数据类

@Serializable
data class Site (
    @SerialName("id")
    val id: Int,
    @SerialName("name")
    val name: String,
    @SerialName("accountId")
    val accountId: Int // 去掉末尾多余的逗号
)

步骤2:定义响应结构类

@Serializable
data class SiteListResponse(
    @SerialName("sites")
    val sites: SitesWrapper
)

@Serializable
data class SitesWrapper(
    @SerialName("count")
    val count: Int,
    @SerialName("site")
    val site: List<Site>
)

步骤3:修改getSitesList方法

suspend fun getSitesList(): List<Site> {
    val response = get("sites/list").body<SiteListResponse>()
    return response.sites.site
}

方案二:自定义序列化器直接提取嵌套数组(无需额外类)

如果不想写多余的响应结构类,可以用Kotlinx Serialization的自定义序列化器,直接定位到sites.site路径。

步骤1:创建自定义序列化器

class NestedListSerializer<T>(private val elementSerializer: KSerializer<T>) : KSerializer<List<T>> {
    override val descriptor: SerialDescriptor = elementSerializer.descriptor

    override fun serialize(encoder: Encoder, value: List<T>) {
        // 仅处理反序列化,序列化逻辑可留空
        TODO("Not needed for deserialization")
    }

    override fun deserialize(decoder: Decoder): List<T> {
        val jsonDecoder = decoder as JsonDecoder
        val jsonElement = jsonDecoder.decodeJsonElement()
        // 定位到sites -> site数组
        val siteArray = jsonElement.jsonObject["sites"]?.jsonObject?.get("site") ?: throw JsonDecodingException(
            decoder = decoder,
            message = "Could not find sites.site array"
        )
        return jsonDecoder.json.decodeFromJsonElement(ListSerializer(elementSerializer), siteArray)
    }
}

步骤2:修改getSitesList方法

suspend fun getSitesList(): List<Site> {
    val serializer = NestedListSerializer(Site.serializer())
    return get("sites/list").body(serializer)
}

方案三:手动解析JSON字符串(快速调试版)

直接获取响应文本后手动解析提取数组,逻辑直观,适合临时调试:

suspend fun getSitesList(): List<Site> {
    val jsonString = get("sites/list").bodyAsText()
    val jsonElement = Json.parseToJsonElement(jsonString)
    // 实际项目中建议替换!!为安全空处理,比如?:抛出自定义异常
    val siteArray = jsonElement.jsonObject["sites"]!!.jsonObject["site"]!!
    return Json.decodeFromJsonElement<List<Site>>(siteArray)
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 01:05:19