You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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
        }
    }
}

关键原因复盘

你原来的代码之所以报错,核心是:

  1. open类触发了kotlinx.serialization的多态序列化逻辑,解析器期望找到多态类型的标识结构
  2. 自定义的load方法直接返回空对象,完全没处理输入中的多态相关数据,导致解析器找不到预期的标记,抛出了"期望'['"的异常(多态序列化默认可能用数组结构存储类型和数据,所以解析器找数组开头的'[')

内容的提问来源于stack exchange,提问作者ligi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 08:55:29