Kotlin泛型嵌套多态序列化:如何注册Pair为多态子类?
Map<String, Any>中的Pair<Int, Int>,注册多态子类失败 错误信息(中文翻译)
主线程异常:java.lang.ExceptionInInitializerError
引起原因:java.lang.IllegalArgumentException: Pair的序列化器无法注册为多态序列化的子类,因为它的类型为OPEN(未绑定具体泛型参数),并非具体类型。若要处理多继承结构,请将其注册为基类。
at kotlinx.serialization.json.internal.PolymorphismValidator.checkKind(PolymorphismValidator.kt:41)
at kotlinx.serialization.json.internal.PolymorphismValidator.polymorphic(PolymorphismValidator.kt:31)
at kotlinx.serialization.modules.SerialModuleImpl.dumpTo(SerializersModule.kt:189)
at kotlinx.serialization.json.JsonImpl.validateConfiguration(Json.kt:358)
at kotlinx.serialization.json.JsonImpl.(Json.kt:352)
at kotlinx.serialization.json.JsonKt.Json(Json.kt:189)
at kotlinx.serialization.json.JsonKt.Json$default(Json.kt:185)
at MainKt.(Main.kt:143)
错误原因
Pair::class是泛型类,对应的序列化器属于OPEN类型(未绑定具体泛型参数),而kotlinx.serialization要求多态子类必须是CONCRETE具体类型(绑定明确泛型参数或非泛型类),因此直接将Pair::class注册为Any的多态子类会触发该错误。
解决方案
需要为具体的Pair<Int, Int>实现序列化器,再将Pair注册为多态基类,最后把Pair::class作为Any的多态子类注册。
完整实现代码
import kotlinx.serialization.* import kotlinx.serialization.descriptors.* import kotlinx.serialization.encoding.* import kotlinx.serialization.json.* import kotlinx.serialization.modules.* // 为Pair<Int, Int>实现自定义序列化器 val pairIntIntSerializer = object : KSerializer<Pair<Int, Int>> { override val descriptor: SerialDescriptor = buildClassSerialDescriptor("Pair") { element("first", Int.serializer().descriptor) element("second", Int.serializer().descriptor) } override fun serialize(encoder: Encoder, value: Pair<Int, Int>) { encoder.encodeStructure(descriptor) { encodeSerializableElement(descriptor, 0, Int.serializer(), value.first) encodeSerializableElement(descriptor, 1, Int.serializer(), value.second) } } override fun deserialize(decoder: Decoder): Pair<Int, Int> { return decoder.decodeStructure(descriptor) { var first = 0 var second = 0 while (true) { when (val index = decodeElementIndex(descriptor)) { 0 -> first = decodeSerializableElement(descriptor, 0, Int.serializer()) 1 -> second = decodeSerializableElement(descriptor, 1, Int.serializer()) CompositeDecoder.DECODE_DONE -> break else -> error("Unexpected index $index") } } first to second } } } fun main() { val module = SerializersModule { // 注册Pair作为多态基类,绑定Pair<Int, Int>的序列化器 polymorphic(Pair::class) { @Suppress("UNCHECKED_CAST") subclass(Pair::class as KClass<Pair<Int, Int>>, pairIntIntSerializer) } // 注册Any的多态子类,包含Int、String和Pair polymorphic(Any::class) { subclass(Int::class, PolymorphicPrimitiveSerializer(Int.serializer())) subclass(String::class, PolymorphicPrimitiveSerializer(String.serializer())) subclass(Pair::class, PolymorphicSerializer(Pair::class)) } } val format = Json { serializersModule = module prettyPrint = true } val mm = mapOf<String, Any>( "int-int pair" to (5 to 10), "test int" to 100, "test string" to "hello" ) val jsoned = format.encodeToString(mm) println(jsoned) val mmDecoded = format.decodeFromString<Map<String, Any>>(jsoned) require(mm == mmDecoded) }
代码说明
- 自定义序列化器:
pairIntIntSerializer专门处理Pair<Int, Int>的序列化/反序列化,符合kotlinx.serialization的规范。 - 多态基类注册:将
Pair作为多态基类,绑定具体的Pair<Int, Int>序列化器(通过@Suppress消除泛型类型转换的警告)。 - Any的多态子类注册:将
Pair::class注册为Any的多态子类,使用PolymorphicSerializer处理多态标识(生成带type和value的JSON结构)。 - JSON格式化:开启
prettyPrint可以输出格式化后的JSON,与期望格式一致。
输出示例
{ "int-int pair": { "type": "Pair", "value": { "first": 5, "second": 10 } }, "test int": { "type": "Int", "value": 100 }, "test string": { "type": "String", "value": "hello" } }
内容的提问来源于stack exchange,提问作者A-_-S

