如何在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
相关产品推荐
相关产品推荐

