3

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

假设您有一个包装类Wrapper,它接收一个字符串content和一个类* type,并且可以通过调用函数输出type通过解析content为 JSON检索到的类对象getObj()

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

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

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

那么,如何使用 kotlinx.serialization 来做到这一点?甚至可能吗?

4

1 回答 1

4

好的,所以还没有人回答这个问题,但我也在 r/Kotlin subreddit 中发布了这个问题。在这里

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

所以,基本上,kotlinx-serialization 确实不适用于KClasses。但是当你考虑它时,你只需要KClass确定如何序列化它。由于这是在您使用 KXS 时在编译时确定的,因此您实际上只需要传递序列化程序(定义如何序列化/反序列化您的类的实际策略)。@Serializable您可以通过调用它来获得每个带有注释的类的序列化.serializer()程序;结果将是类型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 一起使用。

于 2020-10-15T15:15:47.257 回答