Kotlin 序列化子类:“未找到多态序列化器”

问题描述 投票:0回答:1

我正在尝试序列化子类的实例,但输出是意外的。

这是代码(第二个测试与第一个测试仅在

cc: ${c as Child}
处不同):

import kotlinx.serialization.Serializable
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import org.junit.Test

class SerializeTest {
    @Test
    fun one() {
        println("test: one")
        val c: Parent = Child("HI")
        println("c: $c")
        val en = Json.encodeToString(c)
        println("json: $en")
        val de: Parent = Json.decodeFromString(en)
        println("de: $de")
    }

    @Test
    fun two() {
        println("test: two")
        val c: Parent = Child("HI")
        println("c: $c, cc: ${c as Child}")
        val en = Json.encodeToString(c)
        println("json: $en")
        val de: Parent = Json.decodeFromString(en)
        println("de: $de")
    }
}

@Serializable
sealed class Parent(val integer: Int)

@Serializable
class Child (val string: String): Parent(0)

输出:

test: one
c: com.example.CC@415b0b49
json: {"type":"com.example.CC","integer":0,"string":"HI"}
de: com.example.CC@3e6104fc
test: two
c: com.example.CC@62010f5c, cc: com.example.CC@62010f5c
json: {"integer":0,"string":"HI"}

Exception: Polymorphic serializer was not found for missing class discriminator ('null')
JSON input: {"integer":0,"string":"HI"}
...

第一个测试运行良好,但第二个测试失败并出现异常。

任何人都可以解释为什么转换:

c as Child
(编译器已经隐式意识到)导致编码函数在第二次测试中省略
type

kotlin testing serialization polymorphism
1个回答
0
投票

TL;博士

因为图书馆以任何其他方式工作都是不切实际的。


原来是这样的

在某种程度上,你可以说:

type
被省略,因为库就是这样写的。此行为有明确记录

序列化多态类层次结构时,必须确保序列化对象的编译时类型是多态类型,而不是具体类型。

序列化子对象

但是为什么会这样呢?好吧,想想

encodeToString
函数是如何工作的。调用时,它只知道要求序列化的对象的类型。如果该类型是
Child
,它可以直接将对象序列化为
Child
,工作就完成了。

那么,如果编写该库是为了尝试发现

Child
Parent
的子类,并相应地进行序列化,又会怎样呢?实际上这可能是不可能的,因为
Child
Parent
可能规定与自动生成的序列化器不同的序列化器。如果它们发生冲突,图书馆如何知道选择哪一个?它不能轻易保证两者的兼容性。

此外,

Child
可以有多个父类。它应该序列化为哪一个或哪些?

如果您不尝试支持这样的功能,所有这些问题都可以避免。

序列化父对象

现在,当

encodeToString
看到的类型是
Parent
时,函数可以轻松发现它正在处理一个密封类(有一个简单的属性),然后添加
type
鉴别器以促进多态序列化。

您可能知道,如果

Parent
未密封,则不会自动添加类型鉴别器。为此,您必须注册
Child
进行多态序列化。希望您可以看到,以这种方式注册类也提供了
encodeToString
一种了解是否需要添加类型鉴别器的简单方法。

总而言之,Kotlin 团队对其库的工作方式做出了实际的选择。

© www.soinside.com 2019 - 2024. All rights reserved.