我有一门封闭的课程:

sealed class ViewModel {

  data class Loaded(val value : String) : ViewModel()
  object Loading : ViewModel()

}

我如何序列化/反序列化ViewModel类的实例(比方说到JSON格式/从JSON格式)?

我try 使用Genson序列化/反序列化程序库-它可以处理Kotlin数据类,也可以支持多态类型(例如.使用一些元数据来指定具体类型).

However, the library fails on Kotlin object types, as these are singletons without a public constructor. I guess I could write a custom Genson converter to handle it, but maybe there's an easier way to do it?

推荐答案

我最终实现了一个定制的转换器和一个工厂,以便将其正确地插入Genson.

它使用Genson的元数据约定将对象表示为:

{ 
  "@class": "com.example.ViewModel.Loading" 
}

转换器假设设置了useClassMetadata个标志,所以序列化只需要标记一个空对象.对于反序列化,它从元数据解析类名,加载它并获得objectInstance.

object KotlinObjectConverter : Converter<Any> {

override fun serialize(objectData: Any, writer: ObjectWriter, ctx: Context) {
    with(writer) {
        // just empty JSON object, class name will be automatically added as metadata
        beginObject()
        endObject()
    }
}

override fun deserialize(reader: ObjectReader, ctx: Context): Any? =
    Class.forName(reader.nextObjectMetadata().metadata("class"))
        .kotlin.objectInstance
        .also { reader.endObject() }
}

为了确保此转换器仅应用于实际的objects,我使用工厂注册它,该工厂告诉Genson何时使用它,何时退回到默认实现.

object KotlinConverterFactory : Factory<Converter<Any>> {

    override fun create(type: Type, genson: Genson): Converter<Any>? =
        if (TypeUtil.getRawClass(type).kotlin.objectInstance != null) KotlinObjectConverter
        else null

}

工厂可通过builder配置Genson:

GensonBuilder()
        .withConverterFactory(KotlinConverterFactory)
        .useClassMetadata(true) // required to add metadata during serialization
        // some other properties
        .create()

使用链式转换器功能,代码可能会更好,但我还没有时间判断它.

Kotlin相关问答推荐

Kotlin是否针对范围和进度优化sum()?

计算值的Elvis算子

解决Microronaut中多个可能的Bean候选者冲突

Kotlin Coroutine()是如何工作的?S阻止了.

如何在不基于数据 map 的情况下将图例添加到lets plot kotlin

在 detekt 配置文件中找不到某些属性

内容更改后的 var 重新计算

Kotlin 1.2.21 + SimpleXml 2.3.0 - consume List error (must mark set get method)

什么是 .kotlin_builtins 文件,我可以从我的 uberjars 中省略它们吗?

`DataBindingUtil` 中的 `bind`、`inflate` 和 `setContentView` 有什么区别

如果我可以将 Flow 和 StateFlow 与生命周期范围 \ viewLifecycleOwner.lifecycleScope 一起使用,那么在 ViewModel 中使用 LiveData 有什么意义

Kotlin JVM 和 Kotlin Native 有什么区别?

在Kotlin中传递并使用函数作为构造函数参数

用mockk验证属性设置程序吗?

Kotlin:如何从另一个类访问字段?

Kotlin,什么时候按map授权?

Kotlin Flow 收集后无法执行代码

在 Android 12 (SDK 31) 中获取 android.app.ForegroundServiceStartNotAllowedException

Kotlin中默认导入哪些包/函数?

我应该在哪里调用 MobileAds.initialize()?