如何用Kotlinx.Serialization处理JSON多态字段(String/Int)反序列化?
问题原因
你写的序列化器错误调用了beginStructure()解析数据——这个方法是用来处理JSON对象/数组这类结构化数据的,但API返回的reserved_stock是单个原始值(Int或String),所以解码器会抛出“期望对象却找到Int(或String)”的异常。
正确处理方案
直接针对原始值类型做判断,不需要开启结构解析,以下是修正后的代码:
import kotlinx.serialization.* import kotlinx.serialization.json.JsonDecoder import kotlinx.serialization.json.JsonPrimitive @Serializable(with = ReservedStockSerializer::class) sealed class ReservedStock { data class IntValue(val value: Int) : ReservedStock() data class StringValue(val value: String) : ReservedStock() } object ReservedStockSerializer : KSerializer<ReservedStock> { override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("ReservedStock", PrimitiveKind.STRING) override fun serialize(encoder: Encoder, value: ReservedStock) { when (value) { is ReservedStock.IntValue -> encoder.encodeInt(value.value) is ReservedStock.StringValue -> encoder.encodeString(value.value) } } override fun deserialize(decoder: Decoder): ReservedStock { return if (decoder is JsonDecoder) { // 针对JSON格式直接解析原始元素类型 val jsonElement = decoder.decodeJsonElement() when (jsonElement) { is JsonPrimitive -> { if (jsonElement.isInt) { ReservedStock.IntValue(jsonElement.int) } else { ReservedStock.StringValue(jsonElement.content) } } else -> throw SerializationException("ReservedStock 必须是Int或String类型的原始值") } } else { // 适配非JSON解码器,先尝试解析Int,失败则解析String try { ReservedStock.IntValue(decoder.decodeInt()) } catch (e: SerializationException) { ReservedStock.StringValue(decoder.decodeString()) } } } }
代码说明
- 移除结构解析逻辑:不再调用
beginStructure(),直接处理原始值 - JSON格式优化处理:通过
JsonDecoder直接获取JsonElement,判断是Int类型的原始值还是String类型 - 兼容非JSON场景:针对非JSON解码器(比如Protobuf等),用try-catch的方式先尝试解析Int,失败则解析String
- 序列化逻辑对齐:序列化时根据类型直接输出Int或String,保持和API返回格式一致
内容的提问来源于stack exchange,提问作者Stelios Papamichail
相关产品推荐
相关产品推荐

