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

如何在Moshi中处理字段类型不匹配数据并设目标属性为null

问题描述

给定如下JSON数据:

{
   "items":[
      {
         "id":"0000301553526",
         "values":{
            "name":{
               "value":{
                  "en_En":"Item"
               },
               "formatted":{
                 
               },
               "attribute":{
                  "group":{
                     "code":null,
                     "label":null
                  },
                  "group_mod":{
                     "code":null,
                     "label":null
                  },
                  "localizable":true,
                  "type":"text",
                  "code":"name",
                  "label":"name",
                  "visible":false,
                  "display_order":null
               }
            },
            "additonal_data":{
               "value":"",
               "attribute":{
                  "group":{
                     "code":null,
                     "label":null
                  },
                  "group_mod":{
                     "code":null,
                     "label":null
                  },
                  "localizable":true,
                  "type":"local",
                  "code":"ABCC",
                  "label":"action",
                  "visible":false,
                  "display_order":null
               }
            }
         }
      }
   ]
}

其中additonal_data对象的value字段预期应为null或String类型,但后端偶尔会返回数组类型。需要忽略类型错误的数据,将该属性设为null。

当前已有如下代码:

class IgnoreDataAdapter<T> private constructor(
    private val delegate: JsonAdapter<T>
) : JsonAdapter<T>() {

    @FromJson
    override fun fromJson(reader: JsonReader): T? {
        reader.setFailOnUnknown(false)
        val peeked = reader.peekJson()
        val result: T? = try {
            delegate.fromJson(peeked)
        } catch (e: JsonDataException) {
            null
        } finally {
            peeked.close()
        }
        reader.skipValue()
        return result
    }

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

但该适配器针对整个对象,希望无需逐个解析所有属性,仅将类型错误的目标属性设为null,该如何实现?

解决方案

无需修改整个对象的解析逻辑,只需要给目标字段(additonal_data.value)单独编写自定义适配器,在解析时捕获类型错误并返回null即可。

步骤1:编写单个属性的类型容错适配器

创建专门处理String?类型的适配器,遇到非String/非null的类型时直接返回null:

class SafeStringAdapter : JsonAdapter<String?>() {
    @FromJson
    override fun fromJson(reader: JsonReader): String? {
        return try {
            // 正常解析String或null
            if (reader.peek() == JsonToken.NULL) {
                reader.nextNull()
                null
            } else {
                reader.nextString()
            }
        } catch (e: JsonDataException) {
            // 类型不匹配时跳过当前值并返回null
            reader.skipValue()
            null
        }
    }

    @ToJson
    override fun toJson(writer: JsonWriter, value: String?) {
        writer.value(value)
    }
}

步骤2:在数据类的目标字段上绑定适配器

假设对应的AdditonalData数据类如下,直接在value字段上用@JsonAdapter指定适配器:

data class AdditonalData(
    @JsonAdapter(SafeStringAdapter::class)
    val value: String?,
    val attribute: Attribute
)

// 关联数据类示例
data class Values(
    val name: Name,
    val additonal_data: AdditonalData
)

data class Item(
    val id: String,
    val values: Values
)

data class ApiResponse(
    val items: List<Item>
)

原理说明

  • 该适配器仅作用于标记了@JsonAdapter的单个字段,不会影响其他属性的正常解析。
  • 当后端返回数组等非预期类型时,reader.nextString()会抛出JsonDataException,此时捕获异常、跳过错误值并返回null。
  • 正常的String或null类型会被正常解析,不会触发异常逻辑。

扩展:通用类型容错适配器(可选)

如果后续有其他字段需要类似处理,可以编写通用版本的适配器支持指定目标类型:

class SafeTypeAdapter<T>(private val typeAdapter: JsonAdapter<T>) : JsonAdapter<T?>() {
    @FromJson
    override fun fromJson(reader: JsonReader): T? {
        return try {
            typeAdapter.fromJson(reader)
        } catch (e: JsonDataException) {
            reader.skipValue()
            null
        }
    }

    @ToJson
    override fun toJson(writer: JsonWriter, value: T?) {
        typeAdapter.toJson(writer, value)
    }

    companion object {
        fun <T> create(typeAdapter: JsonAdapter<T>): SafeTypeAdapter<T> {
            return SafeTypeAdapter(typeAdapter)
        }
    }
}

使用时可在字段上直接指定:

@JsonAdapter(SafeTypeAdapter::class)
val value: String?

不过对于String这类简单类型,使用专用适配器更简洁。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 20:04:56