kotlinx.serialization自定义序列化报错:Expected '[', kind: POLYMORPHIC
解决kotlinx.serialization自定义序列化的多态异常问题
你遇到的这个Expected '[', kind: POLYMORPHIC异常,根源在于你把KdfParams声明成了open类——kotlinx.serialization默认会把open类当作多态类型处理,解析时会期望找到多态类型的标识信息(比如默认的@type字段),但你的自定义序列化器完全没处理这部分逻辑,导致解析器找不到它预期的结构,直接报错了。
另外要提一句,你代码里用的KOutput/KInput和save/load方法是旧版API,现在kotlinx.serialization已经换成Encoder/Decoder和serialize/deserialize了,建议同步更新,避免版本兼容问题。
下面给你两种场景的解决方案:
场景1:不需要多态(这个类不会被继承)
最简单的办法就是去掉open关键字,这样序列化器就不会触发多态处理逻辑,自定义序列化就能正常工作:
@Serializable class KdfParams { // 移除open修饰符 var dklen: Int = 0 var salt: String? = null @Serializer(forClass = KdfParams::class) companion object { override fun serialize(output: Encoder, obj: KdfParams) { // 手动构建结构并序列化字段 output.beginStructure(descriptor).apply { encodeIntElement(descriptor, 0, obj.dklen) obj.salt?.let { encodeStringElement(descriptor, 1, it) } endStructure(descriptor) } } override fun deserialize(input: Decoder): KdfParams { val params = KdfParams() input.beginStructure(descriptor).apply { // 循环解析每个字段 loop@ while (true) { when (val index = decodeElementIndex(descriptor)) { CompositeDecoder.DECODE_DONE -> break@loop 0 -> params.dklen = decodeIntElement(descriptor, index) 1 -> params.salt = decodeStringElement(descriptor, index) else -> skipElement(descriptor, index) // 忽略未知字段 } } endStructure(descriptor) } return params } } }
场景2:需要多态(这个类会被子类继承)
如果确实需要保留open类支持多态,那你得在自定义序列化器里手动处理多态类型标识。以JSON格式为例,需要在序列化时写入类型标记,反序列化时读取并判断类型:
@Serializable @Polymorphic // 明确标注这是多态类型 open class KdfParams { var dklen: Int = 0 var salt: String? = null @Serializer(forClass = KdfParams::class) companion object { override fun serialize(output: Encoder, obj: KdfParams) { if (output is JsonEncoder) { // 手动构建包含类型标识的JSON对象 val jsonObj = JsonObject( mapOf( "@type" to JsonPrimitive("KdfParams"), // 类型标记 "dklen" to JsonPrimitive(obj.dklen), "salt" to obj.salt?.let { JsonPrimitive(it) } ?: JsonNull ) ) output.encodeJsonElement(jsonObj) } else { // 非JSON格式的通用序列化逻辑 output.beginStructure(descriptor).apply { encodeIntElement(descriptor, 0, obj.dklen) obj.salt?.let { encodeStringElement(descriptor, 1, it) } endStructure(descriptor) } } } override fun deserialize(input: Decoder): KdfParams { val params = KdfParams() if (input is JsonDecoder) { val jsonObj = input.decodeJsonElement() as JsonObject // 读取字段值 params.dklen = jsonObj["dklen"]?.jsonPrimitive?.int ?: 0 params.salt = jsonObj["salt"]?.jsonPrimitive?.contentOrNull } else { // 非JSON格式的通用反序列化逻辑 input.beginStructure(descriptor).apply { loop@ while (true) { when (val index = decodeElementIndex(descriptor)) { CompositeDecoder.DECODE_DONE -> break@loop 0 -> params.dklen = decodeIntElement(descriptor, index) 1 -> params.salt = decodeStringElement(descriptor, index) else -> skipElement(descriptor, index) } } endStructure(descriptor) } } return params } } }
关键原因复盘
你原来的代码之所以报错,核心是:
open类触发了kotlinx.serialization的多态序列化逻辑,解析器期望找到多态类型的标识结构- 自定义的
load方法直接返回空对象,完全没处理输入中的多态相关数据,导致解析器找不到预期的标记,抛出了"期望'['"的异常(多态序列化默认可能用数组结构存储类型和数据,所以解析器找数组开头的'[')
内容的提问来源于stack exchange,提问作者ligi
相关产品推荐
相关产品推荐

