如何将Kotlin密封类对象像枚举常量一样序列化?
自动生成密封类对象的kotlinx-serialization序列化逻辑
你可以通过Kotlin Symbol Processing (KSP) 配合kotlinx-serialization的注解,自动生成serialName映射、fromSerialName方法以及自定义KSerializer的实现,彻底消除手动维护的冗余。以下是具体实现思路:
1. 基础配置与注解标记
首先给你的密封类及其中的对象添加必要注解:
// 标记密封类使用自动生成的序列化器(后续由KSP生成) @Serializable(with = AutoGeneratedDomainObjectSerializer::class) sealed class DomainObject<T> { // 给每个对象指定序列化后的字符串值 @SerialName("user") object User : DomainObject<String>() @SerialName("product") object Product : DomainObject<Int>() @SerialName("order") object Order : DomainObject<Double>() }
2. 用KSP自动生成核心逻辑
编写一个KSP处理器,扫描带有@Serializable的密封类及其子对象的@SerialName注解,自动生成以下代码:
自动生成的fromSerialName方法
fun <T> DomainObject.Companion.fromSerialName(name: String): DomainObject<T>? = when (name) { "user" -> DomainObject.User as DomainObject<T> "product" -> DomainObject.Product as DomainObject<T> "order" -> DomainObject.Order as DomainObject<T> else -> null }
自动生成的自定义序列化器
object AutoGeneratedDomainObjectSerializer : KSerializer<DomainObject<*>> { override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("DomainObject", PrimitiveKind.STRING) override fun serialize(encoder: Encoder, value: DomainObject<*>) { val serialName = value::class.annotations .filterIsInstance<SerialName>() .firstOrNull() ?.value ?: error("对象${value::class.simpleName}未标记@SerialName注解") encoder.encodeString(serialName) } override fun deserialize(decoder: Decoder): DomainObject<*> { val serialName = decoder.decodeString() return DomainObject.fromSerialName(serialName) ?: error("无法识别序列化名称:$serialName") } }
3. 处理器核心逻辑要点
你的KSP处理器需要完成以下操作:
- 识别带有
@Serializable且指定了自定义序列化器的密封类 - 遍历密封类的所有对象子类,收集每个对象的
@SerialName值 - 生成
fromSerialName的when分支逻辑,映射字符串到对应对象 - 生成序列化器的实现代码,复用收集到的
serialName映射关系
这样,每次新增密封类对象时,只需添加@SerialName注解,KSP会自动更新所有序列化相关逻辑,无需手动修改映射表或序列化器。
内容的提问来源于stack exchange,提问作者Daniel Schröder
相关产品推荐
相关产品推荐

