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

如何让Moshi适配器忽略多态列表中格式错误的已知类型元素?

解决Moshi多态解析时忽略缺失必填字段的已知类型元素

方案思路

通过装饰器模式包装子类的JsonAdapter,捕获单个子类解析时的JsonDataException,返回null;最后在列表解析完成后过滤掉null元素,既保留必填字段的类型安全,又能跳过无效元素。

具体实现步骤

1. 实现容错Adapter装饰器

创建通用的LenientAdapter,用来包装目标Adapter并捕获解析异常:

class LenientAdapter<T>(private val delegate: JsonAdapter<T>) : JsonAdapter<T>() {
    override fun fromJson(reader: JsonReader): T? {
        return try {
            delegate.fromJson(reader)
        } catch (e: JsonDataException) {
            // 捕获必填字段缺失等解析异常,返回null标记无效元素
            null
        }
    }

    override fun toJson(writer: JsonWriter, value: T?) {
        delegate.toJson(writer, value)
    }
}

2. 配置Moshi时绑定容错Adapter

在Moshi构建过程中,给每个多态子类绑定包装后的容错Adapter,同时保留未知类型的默认值处理:

val moshi = Moshi.Builder()
    .add(
        PolymorphicJsonAdapterFactory.of(Animal::class.java, "type")
            .withSubtype(Fish::class.java, Type.FISH.name)
            .withSubtype(Bird::class.java, Type.BIRD.name)
            .withDefaultValue(null) // 未知类型直接返回null,后续统一过滤
    )
    // 为Fish类绑定容错Adapter
    .add(object : ObjectFactory<Fish> {
        override fun create(): Fish = throw UnsupportedOperationException()
    }) { type, annotations, moshi ->
        if (type == Fish::class.java) LenientAdapter(moshi.adapter(type, annotations)) else null
    }
    // 为Bird类绑定容错Adapter
    .add(object : ObjectFactory<Bird> {
        override fun create(): Bird = throw UnsupportedOperationException()
    }) { type, annotations, moshi ->
        if (type == Bird::class.java) LenientAdapter(moshi.adapter(type, annotations)) else null
    }
    .build()

3. 解析列表后过滤无效元素

定义包含列表的数据类,解析完成后过滤掉所有null元素:

data class AnimalList(val animals: List<Animal?>)

// 解析示例
val json = """{
  "animals": [
    {
      "type": "FISH"
    },
    {
      "type": "ANIMAL",
      "requiredField": "blablabla"
    },
    {
      "type": "BIRD",
      "requiredField": "sparrow"
    }
  ]
}"""

val adapter = moshi.adapter(AnimalList::class.java)
val animalList = adapter.fromJson(json)
val validAnimals = animalList?.animals?.filterNotNull() ?: emptyList()
// validAnimals 仅包含正常解析的Bird实例

方案优势

  • 保留Kotlin数据类的必填字段定义,保证类型安全,无需将所有字段改为可选
  • 统一处理未知类型和已知类型解析失败的场景,最终得到纯净的有效元素列表
  • 装饰器模式对原有代码侵入性低,可快速扩展到其他多态子类

内容的提问来源于stack exchange,提问作者Camilo Sierra Rodriguez

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 23:23:10