使用kotlinx.serialization解析Kotlin中多类型字段(字符串/对象)
用kotlinx.serialization解析多类型字段(String/自定义Object)
要处理同一个字段既可能是String又可能是自定义Object的情况,最直接的方案是用密封类+自定义序列化器实现类型适配,具体步骤如下:
1. 定义密封类统一字段类型
先创建一个密封类,用来包裹两种可能的取值类型:
@Serializable(with = SomethingFieldSerializer::class) sealed class SomethingField { // 对应String类型的情况 data class StringValue(val value: String) : SomethingField() // 对应自定义Object的情况 data class ObjectValue(val data: SomethingObject) : SomethingField() } @Serializable data class SomethingObject( val list1: List<Int>, val list2: List<Int>, )
2. 实现自定义序列化器
编写自定义序列化器,判断JSON元素的类型后分别解析成对应的密封类实例:
object SomethingFieldSerializer : KSerializer<SomethingField> { override val descriptor: SerialDescriptor = buildClassSerialDescriptor("SomethingField") override fun deserialize(decoder: Decoder): SomethingField { val jsonElement = decoder.decodeJsonElement() return when (jsonElement) { // 解析String类型 is JsonPrimitive -> { require(jsonElement.isString) { "Expected String type for somethingField" } SomethingField.StringValue(jsonElement.content) } // 解析自定义Object类型 is JsonObject -> { val objectData = decoder.json.decodeFromJsonElement<SomethingObject>(jsonElement) SomethingField.ObjectValue(objectData) } else -> throw SerializationException("Unsupported type for somethingField") } } override fun serialize(encoder: Encoder, value: SomethingField) { // 如需序列化回后端,处理反向逻辑 when (value) { is SomethingField.StringValue -> encoder.encodeString(value.value) is SomethingField.ObjectValue -> encoder.encodeSerializableValue(SomethingObject.serializer(), value.data) } } }
3. 修改目标数据类
将原SomeObject中的somethingField类型替换为密封类SomethingField:
@Serializable data class SomeObject( // 其他字段... val somethingField: SomethingField )
使用示例
解析后可通过when表达式安全处理两种情况:
val someObject = Json.decodeFromString<SomeObject>(jsonString) when (someObject.somethingField) { is SomethingField.StringValue -> { val strValue = (someObject.somethingField as SomethingField.StringValue).value // 处理字符串逻辑 } is SomethingField.ObjectValue -> { val objectData = (someObject.somethingField as SomethingField.ObjectValue).data // 处理对象逻辑 } }
这种方案的优势是类型安全,编译期就能覆盖所有可能的取值情况,避免运行时类型转换错误。
内容的提问来源于stack exchange,提问作者Сергей Беляков
相关产品推荐
相关产品推荐

