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

