Kotlinx 序列化:如何绕过反序列化的具体类型参数?

Kotlinx Serialization: How to circumvent reified typeargs for deserialization?

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

假设你有一个包装器 class Wrapper,它接受一个字符串 content 和一个 class* type 并且可以输出一个对象 class type 通过调用函数 getObj():

content 解析为 JSON 按需检索
class Wrapper<T>(private val content: String, /*private val type: KClass<*>*/) {
    fun getObj(): T {
        // ?
    }
}

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

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

那么,如何使用 kotlinx.serialization 执行此操作?有可能吗?

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

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

所以,基本上,kotlinx-serialization 确实不适用于 KClasses。但是仔细一想,只需要KClass就可以确定怎么序列化了。因为当你使用 KXS 时,这是在 compile-time 确定的,你实际上只需要传递序列化器(定义如何序列化/反序列化你的 class 的实际策略)。您可以通过调用 .serializer() 为每个用 @Serializable 注释的 class 获得一个序列化程序;结果将是 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 一起使用。