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<T>(content)
,其中T
是目标类型,content
是 JSON 字符串。现在,T
被定义为具体化(以便可以在运行时处理该类型)并且只能用另一个具体化的类型参数或实际的类引用来填充。我不能使用另一个具体化的类型参数,因为我在一个类的上下文中,一个类不能有具体化的类型参数。我也不能使用实际的类引用,因为类的用户应该能够使用不同的目标来构造它,例如他们决定目标是什么,而不是我。
那么,我该如何使用 kotlinx.serialization 来做到这一点?有没有可能?
【问题讨论】:
抱歉,我不明白使用KClass
有什么问题,就像您在构造函数中显示的那样(我认为应该是 KClass<T>
)。
据我所知,kotlinx.serialization 不需要KClass
es,因为它是一个多平台库,而且反射只在JVM上可用,它也可以不使用反射。如果它适用于KClass
,我会使用它。因此,如果可能,请纠正我并告诉我该怎么做
@user AFAIK 内联类仍然是实验性的(虽然这不是一个大问题),但真正的问题是我想做的不仅仅是一个简单的包装类,当然。问题中的包装类仅显示问题的最简化解释。实际上,除其他外,该类还应该进行一些缓存。我认为很明显,对于缓存,我需要多个字段。因此我不能使用内联类
【参考方案1】:
好的,所以还没有人回答这个问题,但我也在 r/Kotlin 子版块中发布了这个问题。 Here it is.
实际上我在那里得到了答案(感谢 u/JakeWharton),并且由于您在 Google 上搜索了相同的问题,您可能会遇到这个 *** 问题,您可能很高兴在这里找到答案。所以这是我尝试解释答案:
所以,基本上,kotlinx-serialization 确实不适用于KClass
es。但是细想一下,只需要KClass
就可以确定如何序列化了。而且由于这是在您使用 KXS 时在编译时确定的,因此您实际上只需要传递序列化程序(定义如何序列化/反序列化您的类的实际策略)。您可以通过在其上调用.serializer()
来为每个带有@Serializable
注释的类获取序列化程序;结果将是KSerializer<T>
类型。所以,而不是拥有
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 进行反序列化?的主要内容,如果未能解决你的问题,请参考以下文章