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

如何为Kotlin Serializer实现动态SerialName注解?

Kotlin Serialization 实现动态字段名(动态SerialName)

要实现动态变化的字段名,直接修改@SerialName注解是行不通的——因为注解是编译期确定的,无法在运行时动态变更。正确的做法是给整个WeatherResponse类编写自定义序列化器,在序列化/反序列化阶段动态处理字段名。

你的自定义序列化器问题分析

你之前写的序列化器是针对String类型的,完全没覆盖WeatherResponse的结构逻辑,这才导致了Field 'weatherData' is required的错误。而且你的序列化逻辑错误地尝试编码两个字符串元素,和实际API返回的“动态键对应WeatherData对象”的结构不匹配。

正确实现方案

假设你的WeatherData定义如下:

@Serializable
data class WeatherData(val temp: Double, val humidity: Int)

给WeatherResponse编写自定义序列化器:

@Serializable(with = WeatherResponseSerializer::class)
data class WeatherResponse(val weatherData: WeatherData)

object WeatherResponseSerializer : KSerializer<WeatherResponse> {
    override val descriptor = SerialDescriptor("com.test.WeatherResponse", SerialKind.Structure)

    override fun serialize(encoder: Encoder, value: WeatherResponse) {
        val dynamicFieldName = getWeatherID()
        encoder.encodeStructure(descriptor) {
            // 传入动态字段名,序列化WeatherData
            encodeSerializableElement(descriptor, 0, WeatherData.serializer(), value.weatherData, dynamicFieldName)
        }
    }

    override fun deserialize(decoder: Decoder): WeatherResponse {
        val dynamicFieldName = getWeatherID()
        return decoder.decodeStructure(descriptor) {
            var targetData: WeatherData? = null
            while (true) {
                val index = decodeElementIndex(descriptor)
                if (index == CompositeDecoder.DECODE_DONE) break
                // 匹配动态字段名
                if (decodeElementName(descriptor, index) == dynamicFieldName) {
                    targetData = decodeSerializableElement(descriptor, index, WeatherData.serializer())
                } else {
                    // 跳过其他未知字段,避免解析失败
                    skipElement(descriptor, index)
                }
            }
            // 校验必填字段
            targetData ?: throw SerializationException("Missing required field: $dynamicFieldName")
        }.let { WeatherResponse(it) }
    }

    // 这里替换成你实际获取动态字段名的逻辑
    // 比如根据之前的API响应、全局状态等返回对应字段名
    private fun getWeatherID(): String {
        return "some_weather_id" // 示例值,可动态返回"another_weather_id"等
    }
}

关键逻辑说明

  1. 绑定序列化器:通过@Serializable(with = ...)指定WeatherResponse使用自定义序列化器
  2. 序列化阶段:调用encodeSerializableElement时传入动态字段名,将weatherData序列化为对应键的对象
  3. 反序列化阶段:遍历所有字段,通过decodeElementName匹配动态字段名,找到后解析WeatherData;其他未知字段直接跳过
  4. 必填校验:最后检查目标字段是否存在,不存在则抛出序列化异常

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 16:53:09