kotlinx.serialization泛型ConcurrentLinkedQueue序列化多态错误排查
我需要将继承自密封类A的数据类B、C序列化到java.util.ConcurrentLinkedQueue中,相关代码如下:
@Serializable sealed class A @Serializable data class B( val x: String, val y: Int, val z: Boolean ) : A() @Serializable data class C( val a: String, val b: Int, val c: Boolean ) : A() @Serializable data class MyServiceCache( val someOtherProp: String = "Hello World", @Serializable(with = ConcurrentLinkedQueueSerializer::class) val networkCallQueue: ConcurrentLinkedQueue<A> = ConcurrentLinkedQueue(), )
同时实现了自定义序列化器:
class ConcurrentLinkedQueueSerializer<T>( private val dataSerializer: KSerializer<List<T>> ) : KSerializer<ConcurrentLinkedQueue<T>> { override val descriptor: SerialDescriptor = dataSerializer.descriptor override fun serialize(encoder: Encoder, value: ConcurrentLinkedQueue<T>) = dataSerializer.serialize( encoder, value.toList() ) override fun deserialize(decoder: Decoder): ConcurrentLinkedQueue<T> = ConcurrentLinkedQueue(dataSerializer.deserialize(decoder)) }
代码编译正常,但运行时序列化抛出如下错误:
Caused by: java.lang.IllegalArgumentException: Polymorphic value has not been read for class null at kotlinx.serialization.internal.AbstractPolymorphicSerializer.deserialize(AbstractPolymorphicSerializer.kt:67) at com.my.app.service.network.ConcurrentLinkedQueueSerializer.deserialize(MyServiceCache.kt:35) at com.my.app.service.network.ConcurrentLinkedQueueSerializer.deserialize(MyServiceCache.kt:27) at kotlinx.serialization.json.internal.StreamingJsonDecoder.decodeSerializableValue(StreamingJsonDecoder.kt:69) at kotlinx.serialization.encoding.AbstractDecoder.decodeSerializableValue(AbstractDecoder.kt:43) at kotlinx.serialization.encoding.AbstractDecoder.decodeSerializableElement(AbstractDecoder.kt:70) at kotlinx.serialization.json.internal.StreamingJsonDecoder.decodeSerializableElement(StreamingJsonDecoder.kt:168) at com.my.app.service.network.MyServiceCache$$serializer.deserialize(MyServiceCache.kt:16) at com.my.app.service.network.MyServiceCache$$serializer.deserialize(MyServiceCache.kt:16) at kotlinx.serialization.json.internal.StreamingJsonDecoder.decodeSerializableValue(StreamingJsonDecoder.kt:69) at kotlinx.serialization.json.Json.decodeFromString(Json.kt:107)
我已参考官方文档实现自定义序列化器,但仍出现该错误,请问我的自定义序列化器存在什么问题?
核心问题
你的自定义序列化器没有正确处理密封类的多态序列化上下文。当直接使用KSerializer<List<T>>时,对于密封类A的子类,序列化器无法获取多态序列化所需的类型鉴别信息,导致反序列化时无法识别具体子类类型,抛出Polymorphic value has not been read错误。
修复步骤
调整序列化器的上下文传递逻辑
自定义序列化器需要通过元素类型的序列化器来构建列表序列化器,而不是直接接收列表序列化器,这样才能携带多态类型的鉴别信息。修改自定义序列化器实现
重构ConcurrentLinkedQueueSerializer,让它能正确处理多态类型:class ConcurrentLinkedQueueSerializer<T> @SerializerConstructorMarker constructor( private val elementSerializer: KSerializer<T> ) : KSerializer<ConcurrentLinkedQueue<T>> { override val descriptor: SerialDescriptor = SerialDescriptor("ConcurrentLinkedQueue", elementSerializer.descriptor) override fun serialize(encoder: Encoder, value: ConcurrentLinkedQueue<T>) { val listSerializer = ListSerializer(elementSerializer) listSerializer.serialize(encoder, value.toList()) } override fun deserialize(decoder: Decoder): ConcurrentLinkedQueue<T> { val listSerializer = ListSerializer(elementSerializer) return ConcurrentLinkedQueue(listSerializer.deserialize(decoder)) } companion object : KSerializerFactory { @Suppress("UNCHECKED_CAST") override fun <T> create(type: KType, annotations: List<Annotation>): KSerializer<T>? { val elementType = type.arguments.first().type ?: return null val elementSerializer = serializer(elementType) return ConcurrentLinkedQueueSerializer(elementSerializer) as KSerializer<T> } } }简化
MyServiceCache的序列化注解
无需手动指定序列化器的泛型参数,让序列化框架自动推导:@Serializable data class MyServiceCache( val someOtherProp: String = "Hello World", val networkCallQueue: ConcurrentLinkedQueue<A> = ConcurrentLinkedQueue(), )若需显式指定,保留
@Serializable(with = ConcurrentLinkedQueueSerializer::class)即可,框架会通过KSerializerFactory自动获取正确的元素序列化器。确认密封类的多态配置
Kotlin Serialization会自动处理密封类的多态序列化,无需额外配置框架会自动生成类型鉴别器。如果使用JSON格式,确保Json实例的配置未禁用多态相关功能。
关键说明
- 原序列化器直接接收
KSerializer<List<T>>,但当T为密封类时,这个列表序列化器不包含多态类型的鉴别信息,反序列化时无法区分B和C。 - 修改后的序列化器通过
ListSerializer(elementSerializer)构建列表序列化器,elementSerializer是密封类A的多态序列化器,能正确处理类型鉴别逻辑。
内容的提问来源于stack exchange,提问作者toshiomagic

