[英]Polymorphic serialization of sealed hierarchies with generic type parameters
使用 Kotlin 序列化,我想使用密封层次结构中的类型参数对通用数据 class 进行序列化和反序列化(到 JSON)。 但是,我得到一个运行时异常。
要重现问题:
import kotlinx.serialization.*
import kotlin.test.Test
import kotlin.test.assertEquals
/// The sealed hierarchy used a generic type parameters:
@Serializable
sealed interface Coded {
val description: String
}
@Serializable
@SerialName("CodeOA")
object CodeOA: Coded {
override val description: String = "Code Object OA"
}
@Serializable
@SerialName("CodeOB")
object CodeOB: Coded {
override val description: String = "Code Object OB"
}
/// Simplified class hierarchy
@Serializable
sealed interface NumberedData {
val number: Int
}
@Serializable
@SerialName("CodedData")
data class CodedData<out C : Coded> (
override val number: Int,
val info: String,
val code: C
): NumberedData
internal class GenericSerializerTest {
@Test
fun `polymorphically serialize and deserialize a CodedData instance`() {
val codedData: NumberedData = CodedData(
number = 42,
info = "Some test",
code = CodeOB
)
val codedDataJson = Json.encodeToString(codedData)
val codedDataDeserialized = Json.decodeFromString<NumberedData>(codedDataJson)
assertEquals(codedData, codedDataDeserialized)
}
}
在以下运行时异常中运行测试结果:
kotlinx.serialization.SerializationException: Class 'CodeOB' is not registered for polymorphic serialization in the scope of 'Coded'.
Mark the base class as 'sealed' or register the serializer explicitly.
这个错误消息对我来说没有意义,因为两个层次结构都被密封并标记为@Serializable
。
我不明白问题的根本原因 - 我是否需要显式注册其中一个插件生成的序列化程序? 还是我需要推出自己的序列化程序? 为什么会这样呢?
我正在使用 Kotlin 1.7.20 和 kotlinx.serialization 1.4.1
免责声明:我不认为我的解决方案非常令人满意,但我现在找不到更好的方法。
关于密封类状态的 KotlinX 序列化文档(强调我的):
您必须确保序列化的 object 的编译时类型是多态的,而不是具体的。
在文档的以下示例中,我们看到序列化子 class 而不是父 class 阻止它使用父(多态)类型反序列化。
在你的情况下,你有嵌套的多态类型,所以我认为这更复杂。 为了使序列化和反序列化工作,我尝试了多种方法,最后,我发现使它工作的唯一方法是:
code
属性:@Serializable
@SerialName("CodedData")
data class CodedData (
override val number: Int,
val info: String,
val code: Coded
): NumberedData
NumberedData
,以确保触发多态性:Json.encodeToString<NumberedData>(codedData)
使用基于您自己的单元测试的小主程序进行测试:
fun main() {
val codedData = CodedData(
number = 42,
info = "Some test",
code = CodeOB
)
val json = Json.encodeToString<NumberedData>(codedData)
println(
"""
ENCODED:
--------
$json
""".trimIndent()
)
val decoded = Json.decodeFromString<NumberedData>(json)
println(
"""
DECODED:
--------
$decoded
""".trimIndent()
)
}
它打印:
ENCODED:
--------
{"type":"CodedData","number":42,"info":"Some test","code":{"type":"CodeOB"}}
DECODED:
--------
CodedData(number=42, info=Some test, code=CodeOB(description = Code Object OB))
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.