Kotlin泛型序列化问题:密封接口自动生成的多态序列化器未生效
这是预期行为,并非bug或操作错误,原因如下:
密封类型自动多态序列化的适用范围
kotlinx.serialization对密封类/接口的自动多态序列化支持,仅在直接使用该密封类型的序列化器时生效。比如直接序列化Element实例:
val elementJson = json.encodeToString(Element.serializer(), FlagElement(false))
这种场景下不需要手动配置polymorphic(Element::class),编译器会自动生成包含所有子类的序列化器。
但当密封类型作为泛型参数被间接包裹在另一个多态类型中(如你的BaseContainer<Element>),并且通过多态序列化BaseContainer时,情况就不同了:此时序列化/反序列化的上下文是BaseContainer的多态规则,kotlinx.serialization无法自动关联到Element的子类序列化器,必须显式在SerializersModule中声明Element的多态配置。
为什么手动配置后能正常工作
当你取消注释polymorphic(Element::class)的代码块后,SerializersModule中同时包含了BaseContainer和Element的多态规则:
val containerSerializerModule = SerializersModule { polymorphic(BaseContainer::class) { subclass(ElementContainer.serializer(Element.serializer())) } polymorphic(Element::class) { subclass(FlagElement::class) subclass(CountElement::class) // 也可以用更简洁的写法:subclass<FlagElement>(), subclass<CountElement>() } }
反序列化时,解析ElementContainer中的element字段时,就能从模块中找到FlagElement或CountElement的序列化器,因此测试可以通过。
补充验证
如果你的测试不需要多态序列化BaseContainer,而是直接序列化ElementContainer<Element>,即使不配置Element的多态规则也能正常工作:
@Test fun `serialize and deserialize element container directly`() { val container = ElementContainer(FlagElement(false)) val containerJson = json.encodeToString(container) val containerDeserialized = json.decodeFromString<ElementContainer<Element>>(containerJson) assertEquals(container, containerDeserialized) }
这进一步证明,问题仅出现在多态序列化外层容器的场景下,必须显式配置内层密封类型的多态规则。
内容的提问来源于stack exchange,提问作者Ulrich Schuster

