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

如何在Kotlin中用kotlinx.serialization序列化/反序列化嵌套JSON

实现方案

你可以通过为User和Asset分别自定义KSerializer来跳过JSON中多余的嵌套层级,不需要改动原有数据模型结构,具体实现如下:

第一步:实现Asset的自定义序列化器

每个Asset实体在JSON中被包裹在data字段下,自定义序列化器直接读取data节点的内容反序列化为Asset即可:

import kotlinx.serialization.*
import kotlinx.serialization.descriptors.*
import kotlinx.serialization.encoding.*
import kotlinx.serialization.json.*

object AssetSerializer : KSerializer<Asset> {
    override val descriptor: SerialDescriptor = buildClassSerialDescriptor("AssetWrapper")

    @OptIn(ExperimentalSerializationApi::class)
    override fun deserialize(decoder: Decoder): Asset {
        val jsonInput = decoder as JsonDecoder
        val jsonObject = jsonInput.decodeJsonElement().jsonObject
        val assetElement = jsonObject["data"] ?: throw SerializationException("Missing data field for Asset")
        return jsonInput.json.decodeFromJsonElement<Asset>(assetElement)
    }

    override fun serialize(encoder: Encoder, value: Asset) {
        val jsonOutput = encoder as JsonEncoder
        val assetElement = jsonOutput.json.encodeToJsonElement(value)
        jsonOutput.encodeJsonElement(buildJsonObject {
            put("data", assetElement)
        })
    }
}

第二步:实现User的自定义序列化器

User实体外层有data包裹,同时assets列表嵌套在body字段下,需要处理两层额外嵌套:

object UserSerializer : KSerializer<User> {
    override val descriptor: SerialDescriptor = buildClassSerialDescriptor("UserWrapper")

    @OptIn(ExperimentalSerializationApi::class)
    override fun deserialize(decoder: Decoder): User {
        val jsonInput = decoder as JsonDecoder
        val rootObj = jsonInput.decodeJsonElement().jsonObject
        val userDataObj = rootObj["data"]?.jsonObject ?: throw SerializationException("Missing top level data field")
        
        val id = userDataObj["id"]!!.jsonPrimitive.content
        val name = userDataObj["name"]!!.jsonPrimitive.content
        val assetsList = userDataObj["body"]?.jsonObject?.get("assets")?.jsonArray ?: throw SerializationException("Missing body.assets field")
        
        // 用AssetSerializer解析列表里的每个元素
        val assets = assetsList.map { 
            jsonInput.json.decodeFromJsonElement(AssetSerializer, it) 
        }
        return User(id, name, assets)
    }

    override fun serialize(encoder: Encoder, value: User) {
        val jsonOutput = encoder as JsonEncoder
        // 组装嵌套结构
        val assetsArray = buildJsonArray {
            value.assets.forEach { asset ->
                add(jsonOutput.json.encodeToJsonElement(AssetSerializer, asset))
            }
        }
        val userDataObj = buildJsonObject {
            put("id", value.id)
            put("name", value.name)
            put("body", buildJsonObject {
                put("assets", assetsArray)
            })
        }
        val rootObj = buildJsonObject {
            put("data", userDataObj)
        }
        jsonOutput.encodeJsonElement(rootObj)
    }
}

第三步:给数据类绑定序列化器

给原有数据类加上@Serializable注解,指定对应的自定义序列化器:

@Serializable(with = UserSerializer::class)
data class User(val id: String, val name: String, val assets: List<Asset>)

@Serializable(with = AssetSerializer::class)
data class Asset(val id: String, val sku: String, val name: String)

第四步:直接使用原有API解析即可

不需要改原有调用逻辑,直接用Json.decodeFromString<User>(jsonStr)就可以正常解析,序列化也可以直接用Json.encodeToString(user)生成符合目标结构的JSON:

// 解析示例
val user = Json.decodeFromString<User>(yourJsonString)
// 序列化示例
val serializedJson = Json.encodeToString(user)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.25 14:54:05