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

如何控制Kotlinx Serialization的多态布局,实现带外部判别器的JSON反序列化?

解决Kotlinx Serialization反序列化外层判别器的多态JSON问题

针对你遇到的问题——JSON里的多态判别器type在对象外层,而Kotlinx Serialization默认期望判别器和属性在同一层级——我们可以通过自定义序列化器来适配这种结构,下面是具体实现步骤:

1. 修正Kotlin类型定义(修正笔误)

首先,你的原始Kotlin代码里B类的属性名和JSON里的bProp不匹配,先修正这个问题:

@Serializable(with = BaseSerializer::class) // 关联自定义序列化器
sealed class Base

@Serializable
class A(val aProp: Boolean) : Base()

@Serializable
class B(val bProp: String) : Base() // 修正属性名为bProp,对应JSON里的字段

@Serializable
class BaseList(val someList: List<Base>)

2. 实现自定义序列化器

我们给Base类写一个自定义序列化器,专门处理{"type": "...", "value": {...}}的嵌套结构:

object BaseSerializer : KSerializer<Base> {
    // 定义序列化描述符,匹配JSON的结构
    override val descriptor: SerialDescriptor = buildClassSerialDescriptor("Base") {
        element("type", String.serializer().descriptor)
        element("value", JsonElement.serializer().descriptor)
    }

    // 序列化逻辑(如果需要将对象转回JSON的话)
    override fun serialize(encoder: Encoder, value: Base) {
        val jsonEncoder = encoder as JsonEncoder
        // 将子类实例转为JsonElement
        val valueJson = when (value) {
            is A -> Json.encodeToJsonElement(A.serializer(), value)
            is B -> Json.encodeToJsonElement(B.serializer(), value)
        }
        // 包装成外层type+value的结构
        jsonEncoder.encodeJsonElement(
            JsonObject(
                mapOf(
                    "type" to JsonPrimitive(value::class.simpleName),
                    "value" to valueJson
                )
            )
        )
    }

    // 反序列化逻辑(核心处理部分)
    override fun deserialize(decoder: Decoder): Base {
        val jsonDecoder = decoder as JsonDecoder
        val jsonObject = jsonDecoder.decodeJsonElement().jsonObject

        // 提取判别器和属性内容,做基础校验
        val type = jsonObject["type"]?.jsonPrimitive?.content ?: error("JSON缺少必填字段:type")
        val valueJson = jsonObject["value"] ?: error("JSON缺少必填字段:value")

        // 根据type匹配对应的子类并解码
        return when (type) {
            "A" -> Json.decodeFromJsonElement(A.serializer(), valueJson)
            "B" -> Json.decodeFromJsonElement(B.serializer(), valueJson)
            else -> error("不支持的类型:$type")
        }
    }
}

3. 测试反序列化

现在你可以直接用标准的Json.decodeFromString来解析目标JSON了:

val targetJson = """{"someList": [ {"type": "A", "value": {"aProp": false } }, {"type": "B", "value": {"bProp": "1" } } ] }"""
val result = Json.decodeFromString(BaseList.serializer(), targetJson)

// 验证结果
println(result.someList[0]) // 输出:A(aProp=false)
println(result.someList[1]) // 输出:B(bProp=1)

扩展说明

  • 如果后续新增Base的子类,只需要在序列化器的when分支里添加对应的类型判断和解码逻辑即可。
  • 序列化器里的错误处理可以根据你的业务需求调整(比如返回默认值而不是抛出异常)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.06 06:55:57