You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何对包含object类型的Kotlin密封类进行序列化/反序列化?

Kotlin密封类(含单例Object)的Genson序列化与反序列化方案

嘿,这个问题我碰到过!Genson对Kotlin数据类的支持确实不错,但单例object确实是个小坑——毕竟Genson默认会尝试用反射创建实例,而单例根本没有公共构造函数。不过咱们通过自定义转换器加上合理的多态配置就能完美解决,下面一步步来:

1. 先把依赖配好

首先确保你引入了Genson的核心库和Kotlin扩展模块,比如Gradle项目里:

implementation 'com.owlike:genson:1.6'
implementation 'com.owlike:genson-kotlin:1.6'

Maven项目的话,对应引入这两个依赖即可。

2. 为单例Object写自定义转换器

针对你的Loading单例,我们需要写一个Genson的Converter,负责它的序列化和反序列化逻辑——序列化时只标记类型,反序列化时直接返回单例实例:

import com.owlike.genson.Context
import com.owlike.genson.Converter
import com.owlike.genson.stream.ObjectReader
import com.owlike.genson.stream.ObjectWriter

object LoadingConverter : Converter<ViewModel.Loading> {
    override fun serialize(obj: ViewModel.Loading, writer: ObjectWriter, ctx: Context) {
        // 序列化时只写入类型标识,因为单例没有其他属性
        writer.beginObject()
        writer.writeString("type", "Loading")
        writer.endObject()
    }

    override fun deserialize(reader: ObjectReader, ctx: Context): ViewModel.Loading {
        // 反序列化时直接返回单例,同时要把流里的内容读完避免报错
        reader.beginObject()
        while (reader.hasNext()) {
            reader.next()
            reader.skipValue()
        }
        reader.endObject()
        return ViewModel.Loading
    }
}

3. 配置Genson实例,整合多态与单例支持

接下来要创建一个自定义配置的Genson实例,既要启用Kotlin支持,还要配置多态类型识别,同时注册咱们的单例转换器:

import com.owlike.genson.Genson
import com.owlike.genson.GensonBuilder

val genson: Genson = GensonBuilder()
    // 启用Genson的Kotlin扩展,处理数据类、空值等特性
    .useKotlin()
    // 开启多态类型元数据支持,指定用"type"字段存储类型标识
    .setWithClassMetadata(true)
    .setClassMetadataFieldName("type")
    // 为Loading单例注册自定义转换器
    .registerConverter(ViewModel.Loading::class.java, LoadingConverter)
    // 映射类型别名:让Genson知道"Loaded"对应Loaded数据类,"Loading"对应Loading单例
    .addAlias("Loaded", ViewModel.Loaded::class.java)
    .addAlias("Loading", ViewModel.Loading::class.java)
    .create()

这里的关键是setClassMetadataFieldName("type")——它告诉Genson在序列化时把类型信息写到type字段里,反序列化时通过这个字段判断具体类型。而addAlias则是把友好的类型名称和实际类绑定起来。

4. 测试序列化与反序列化

现在就可以用这个配置好的genson实例来处理你的密封类实例了:

序列化测试

// 序列化Loaded数据类实例
val loaded = ViewModel.Loaded("Hello Kotlin")
val loadedJson = genson.serialize(loaded)
println(loadedJson)
// 输出结果:{"type":"Loaded","value":"Hello Kotlin"}

// 序列化Loading单例
val loadingJson = genson.serialize(ViewModel.Loading)
println(loadingJson)
// 输出结果:{"type":"Loading"}

反序列化测试

// 反序列化Loaded
val deserializedLoaded = genson.deserialize(loadedJson, ViewModel::class.java)
println(deserializedLoaded is ViewModel.Loaded) // 输出true
println((deserializedLoaded as ViewModel.Loaded).value) // 输出Hello Kotlin

// 反序列化Loading,并且验证是同一个单例
val deserializedLoading = genson.deserialize(loadingJson, ViewModel::class.java)
println(deserializedLoading is ViewModel.Loading) // 输出true
println(deserializedLoading === ViewModel.Loading) // 输出true,证明是同一个单例实例

额外小贴士

  • 如果你的密封类后续新增了其他单例子类,只需要为每个单例写类似的转换器,然后在Genson配置里注册并添加别名即可。
  • 确保addAlias里的名称和序列化时的type字段值完全一致,否则反序列化会找不到对应类型。

内容的提问来源于stack exchange,提问作者Zbigniew Malinowski

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 10:55:15