Kotlin Serialization泛型对象序列化报未找到序列化器问题咨询
问题现象
实现泛型类DetailsRequest的序列化/反序列化操作时,抛出如下报错:
Serializer for class 'DetailsRequest' is not found. Mark the class as @Serializable or provide the serializer explicitly.
这类泛型对象的序列化/反序列化需求完全可以实现,原有代码存在多处逻辑与设计错误,手写的自定义序列化器属于典型的过度设计。
现有代码核心问题
- 类型判断逻辑完全失效:所有
when分支的判断对象错误,descriptor构建、序列化、反序列化逻辑中判断的this::class指向DetailsRequestSerializer单例本身,value::class指向DetailsRequest类实例,永远不可能匹配String/Long/Int等类型,所有分支都会默认走String逻辑,类型判断完全不生效。 - 序列化器设计不符合泛型序列化规则:给泛型类硬绑定了处理星投影
DetailsRequest<*>的固定序列化器,kotlinx.serialization要求泛型类的序列化器必须能感知实际泛型参数的类型,固定的星投影序列化器无法在反序列化时确定泛型参数类型,是触发序列化器找不到报错的核心原因。 - 反序列化流程不符合API规范:直接调用
decoder.decodeString()/decodeLong()等顶层解码方法,没有先进入类结构的元素解码流程,会直接读取错误的JSON位置,解析结果完全不可靠。 - 泛型信息被擦除:扩展方法
convertToDataClass中使用R::class.serializer()获取序列化器,KClass类型不携带泛型参数信息,会直接擦除DetailsRequest<String>中的String泛型,导致无法找到匹配的序列化器。
最简实现方案(无需自定义序列化器)
kotlinx.serialization原生支持泛型类序列化,不需要手写任何自定义序列化逻辑,只需要去掉手动指定的自定义序列化器,给类标记基础的@Serializable注解即可,编译器插件会自动生成适配所有可序列化泛型参数的序列化实现:
@Serializable data class DetailsRequest<out T>(val details: T)
同时修正单元测试中的反序列化逻辑,避免泛型擦除:
class PlaygroundTest { private val json = Json { encodeDefaults = true isLenient = true allowSpecialFloatingPointValues = true allowStructuredMapKeys = true prettyPrint = true useArrayPolymorphism = false ignoreUnknownKeys = true } @Test fun `Details Integration Tests`() { val input = DetailsRequest(details = "New Record") val value = json.encodeToString(input) println("value=[$value]") // 直接用reified类型参数解码,不会擦除泛型信息 val output = json.decodeFromString<DetailsRequest<String>>(value) println("output=[$output]") } }
该原生实现自动支持所有基础类型、自定义数据类、多态类型作为
details的泛型参数,不需要手写类型枚举判断,兼容性远高于自定义硬编码逻辑。如果需要支持多态类型,只需要在Json配置中添加对应多态规则即可。
特殊场景下自定义泛型序列化器的正确写法
如果有特殊逻辑必须自定义序列化器,不要实现为固定的星投影单例对象,要定义为可接收泛型参数序列化器的类,由框架自动注入对应类型的序列化器:
class DetailsRequestSerializer<T>(private val dataSerializer: KSerializer<T>) : KSerializer<DetailsRequest<T>> { override val descriptor: SerialDescriptor = buildClassSerialDescriptor( "DetailsRequest", dataSerializer.descriptor ) { element("details", dataSerializer.descriptor) } override fun serialize(encoder: Encoder, value: DetailsRequest<T>) { encoder.encodeStructure(descriptor) { encodeSerializableElement(descriptor, 0, dataSerializer, value.details) } } override fun deserialize(decoder: Decoder): DetailsRequest<T> { return decoder.decodeStructure(descriptor) { var details: T? = null while (true) { when (val index = decodeElementIndex(descriptor)) { 0 -> details = decodeSerializableElement(descriptor, 0, dataSerializer) CompositeDecoder.DECODE_DONE -> break else -> skipElement(descriptor, index) } } DetailsRequest(details = requireNotNull(details)) } } }
内容的提问来源于stack exchange,提问作者Coach Roebuck
相关产品推荐
相关产品推荐

