Kotlinx.serialization如何实现嵌套类鉴别器JSON多态反序列化
Kotlinx Serialization 嵌套类鉴别器多态反序列化实现
不需要手写全量字段解析的样板代码,有两种轻量实现方案,按需选择即可。
方案一:结构转换方案(推荐,零后续维护成本)
核心思路是在反序列化前做一次极轻量的JSON结构调整,把嵌套在header里的message_type字段平移到data节点内部,之后完全走kotlinx.serialization原生的多态反序列化逻辑。后续新增消息类型只需要按原生规范加@SerialName注解,不需要修改任何序列化配置代码。
- 定义基础数据结构,按原生多态规则配置注解
import kotlinx.serialization.* import kotlinx.serialization.json.* @Serializable data class Message( val header: MessageHeader, @Serializable(with = DataFieldPolymorphicTransformer::class) val data: MessageData ) @Serializable data class MessageHeader( @SerialName("message_type") val messageType: String ) // 按原生多态规则配置类鉴别器 @JsonClassDiscriminator("message_type") sealed interface MessageData // 示例消息子类,直接加对应注解即可,不需要额外配置 @Serializable @SerialName("FooBar") data class FooBarData( // 写该类型对应的所有data字段即可 val exampleField: String ) : MessageData - 一次编写通用的结构转换序列化器,全局可复用
object DataFieldPolymorphicTransformer : JsonTransformingSerializer<MessageData>(MessageData.serializer()) { override fun transformDeserialize(element: JsonElement): JsonElement { // 从解析上下文拿到完整JSON根节点,提取嵌套的类鉴别器 val rootJson = jsonDecoder.decodeJsonElement().jsonObject val messageType = rootJson .getValue("header").jsonObject .getValue("message_type").jsonPrimitive // 把鉴别器字段追加到data节点,交给原生多态逻辑自动匹配子类 return buildJsonObject { element.jsonObject.forEach { (k, v) -> put(k, v) } put("message_type", messageType) } } } - 正常初始化Json实例解析即可
val json = Json { ignoreUnknownKeys = true // 按自己的业务需求配置其他参数 } // 直接调用解析方法 val result = json.decodeFromString<Message>(rawJsonString)
方案二:多态匹配方案(逻辑直观)
如果不想修改JSON结构,可以直接给外层消息实现JsonContentPolymorphicSerializer,手动做类型和序列化器的映射,代码量也非常小。
@Serializable(with = MessagePolymorphicSerializer::class) sealed interface Message { val header: MessageHeader } @Serializable data class FooBarMessage( override val header: MessageHeader, val data: FooBarData ) : Message @Serializable data class MessageHeader( @SerialName("message_type") val messageType: String ) @Serializable data class FooBarData( val exampleField: String ) object MessagePolymorphicSerializer : JsonContentPolymorphicSerializer<Message>(Message::class) { override fun selectDeserializer(element: JsonElement): DeserializationStrategy<Message> { val type = element.jsonObject["header"]?.jsonObject?.get("message_type")?.jsonPrimitive?.content ?: throw SerializationException("header中缺失message_type字段") return when(type) { "FooBar" -> FooBarMessage.serializer() // 新增消息类型在这里加一行映射即可 else -> throw SerializationException("不支持的消息类型: $type") } } }
两种方案都没有冗余的字段解析逻辑,性能和原生多态实现基本一致,代码量远低于手写全量KSerializer。
内容的提问来源于stack exchange,提问作者Max
相关产品推荐
相关产品推荐

