Kotlinx 序列化:如何绕过 reified typeargs 进行反序列化?

Posted

技术标签:

【中文标题】Kotlinx 序列化:如何绕过 reified typeargs 进行反序列化?【英文标题】:Kotlinx Serialization: How to circumvent reified typeargs for deserialization? 【发布时间】:2020-10-01 12:36:52 【问题描述】:

实际上,主要问题仍然是 Kotlin 中的类没有具体的类型参数。但这就是为什么在这种特定情况下这让我感到困扰:

假设您有一个包装类 Wrapper,它接收一个字符串 content 和一个类* type,并且可以通过调用函数getObj():

class Wrapper<T>(private val content: String, /*private val type: KClass<*>*/) 
    fun getObj(): T 
        // ?
    

我想使用 kotlinx.serialization。现在,您可能已经注意到我之前是如何在“class”后面加上星号的。原因如下:是的,Wrapper 必须以some 的方式获取目标类,但是如何?它应该只是 typearg(因为 type erausre 不起作用)还是 KClass 引用(因为我需要一个 reified typearg 而不起作用)?

据我所知,将通用 JSON 解码为可序列化目标类的唯一方法是使用Json.decodeFromString&lt;T&gt;(content),其中T 是目标类型,content 是 JSON 字符串。现在,T 被定义为具体化(以便可以在运行时处理该类型)并且只能用另一个具体化的类型参数或实际的类引用来填充。我不能使用另一个具体化的类型参数,因为我在一个类的上下文中,一个类不能有具体化的类型参数。我也不能使用实际的类引用,因为类的用户应该能够使用不同的目标来构造它,例如他们决定目标是什么,而不是我。

那么,我该如何使用 kotlinx.serialization 来做到这一点?有没有可能?

【问题讨论】:

抱歉,我不明白使用 KClass 有什么问题,就像您在构造函数中显示的那样(我认为应该是 KClass&lt;T&gt;)。 据我所知,kotlinx.serialization 不需要KClasses,因为它是一个多平台库,而且反射只在JVM上可用,它也可以不使用反射。如果它适用于KClass,我会使用它。因此,如果可能,请纠正我并告诉我该怎么做 @user AFAIK 内联类仍然是实验性的(虽然这不是一个大问题),但真正的问题是我想做的不仅仅是一个简单的包装类,当然。问题中的包装类仅显示问题的最简化解释。实际上,除其他外,该类还应该进行一些缓存。我认为很明显,对于缓存,我需要多个字段。因此我不能使用内联类 【参考方案1】:

好的,所以还没有人回答这个问题,但我也在 r/Kotlin 子版块中发布了这个问题。 Here it is.

实际上我在那里得到了答案(感谢 u/JakeWharton),并且由于您在 Google 上搜索了相同的问题,您可能会遇到这个 *** 问题,您可能很高兴在这里找到答案。所以这是我尝试解释答案:

所以,基本上,kotlinx-serialization 确实不适用于KClasses。但是细想一下,只需要KClass就可以确定如何序列化了。而且由于这是在您使用 KXS 时在编译时确定的,因此您实际上只需要传递序列化程序(定义如何序列化/反序列化您的类的实际策略)。您可以通过在其上调用.serializer() 来为每个带有@Serializable 注释的类获取序列化程序;结果将是KSerializer&lt;T&gt; 类型。所以,而不是拥有

class Wrapper<T>(private val content: String, private val type: KClass<T>)

并通过构建它

val wrapper = Wrapper("", Foo::class)

你可以这样做:

class Wrapper<T>(private val content: String, private val serializer: KSerializer<T>)

然后像这样构造它:

val wrapper = Wrapper("", Foo.serializer())

(假设Foo@Serializable注解)

然后您可以使用KSerializer 而不是 typearg 进行序列化和反序列化,如下所示:

val obj: T = Json.decodeFromString(serializer, "[Your JSON String]")
val str: String = Json.encodeToString(serializer, obj)

就是这样!只需将您的常规 (K)Class 方法替换为 KSerializer,它就可以与 KXS 一起使用。

【讨论】:

以上是关于Kotlinx 序列化:如何绕过 reified typeargs 进行反序列化?的主要内容,如果未能解决你的问题,请参考以下文章

如何禁用 kotlinx 序列化多态鉴别器?

如何使用 kotlinx 序列化将值数组反序列化为集合

如何在 Kotlinx 序列化中序列化“任何”类型?

如何使用 kotlinx 序列化 json 的动态键

如何使用 kotlinx 序列化使用 open val 序列化 kotlin 密封类

如何使用 kotlinx.serialization 将库类序列化为 Protobuf?