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

使用Kotlin宽松Json序列化时如何上报接收到的未知Json字段

实现方案:kotlinx.serialization 原生捕获未知 JSON 字段

完全不需要引入额外第三方库,基于 kotlinx.serialization 原生能力即可同时保留宽松解析配置、捕获所有未知字段,具体实现如下:

现有配置保留

你原有的 Json 配置不需要修改:

val jsonConfig = Json {
    ignoreUnknownKeys = true
    isLenient = true
}

核心实现逻辑

通过自定义 Retrofit Converter.Factory,在反序列化前先读取完整 JSON 结构,对比目标类的已知序列化字段,过滤出未知字段上报后再执行正常反序列化逻辑即可。

自定义 Converter 代码

import kotlinx.serialization.descriptors.elementNames
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonElement
import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.decodeFromJsonElement
import kotlinx.serialization.serializer
import okhttp3.ResponseBody
import retrofit2.Converter
import retrofit2.Retrofit
import retrofit2.converter.kotlinx.serialization.KotlinxSerializationConverterFactory
import java.lang.reflect.Type
import kotlin.reflect.KClass
import kotlin.reflect.jvm.kotlin

class UnknownKeyCaptureConverterFactory(
    private val json: Json,
    private val onUnknownKeysFound: (clazz: KClass<*>, unknownKeys: Map<String, JsonElement>) -> Unit
) : Converter.Factory() {
    private val delegateFactory = KotlinxSerializationConverterFactory.create(json)

    override fun responseBodyConverter(
        type: Type,
        annotations: Array<out Annotation>,
        retrofit: Retrofit
    ): Converter<ResponseBody, *>? {
        val delegateConverter = delegateFactory.responseBodyConverter(type, annotations, retrofit)
            ?: return null
        val kClass = (type as? Class<*>)?.kotlin ?: return delegateConverter
        val serializer = json.serializersModule.serializer(type)
        val knownKeys = serializer.descriptor.elementNames.toSet()

        return Converter<ResponseBody, Any> { body ->
            val jsonString = body.string()
            val jsonElement = json.parseToJsonElement(jsonString)
            if (jsonElement is JsonObject) {
                val unknownKeys = jsonElement.filterKeys { it !in knownKeys }
                if (unknownKeys.isNotEmpty()) {
                    onUnknownKeysFound(kClass, unknownKeys)
                }
            }
            json.decodeFromJsonElement(serializer, jsonElement)
        }
    }
}

替换 Retrofit 配置

初始化 Retrofit 时用自定义的 Converter 替换原生的 kotlinx.serialization Converter:

val retrofit = Retrofit.Builder()
    .baseUrl("你的接口基地址")
    .addConverterFactory(
        UnknownKeyCaptureConverterFactory(jsonConfig) { clazz, unknownKeys ->
            // 此处执行未知字段上报逻辑,如打印日志、上报埋点
            println("类 ${clazz.simpleName} 检测到未知字段:$unknownKeys")
            // 你的上报代码
        }
    )
    // 其他配置...
    .build()

注意事项

  • 上述实现默认只捕获最外层 JSON 对象的未知字段,如果需要捕获嵌套对象的未知字段,可扩展逻辑递归遍历所有嵌套的 JsonObject,和对应嵌套类的字段列表做对比即可
  • 常规接口响应大小的场景下,该方案的性能损耗可以忽略,如果需要处理超大响应,可改用 kotlinx.serialization 流式解析 API 配合自定义 Decoder 实现,降低内存占用
  • 原有宽松解析、忽略未知字段的逻辑完全保留,不会影响现有业务的正常运行

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.12 10:27:02