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

使用Moshi解析含多态record字段的JSON遇编码异常的解决方法

解决Moshi解析多态record字段为Map<String, String?>的编码异常问题

异常com.squareup.moshi.JsonEncodingException的根源是record字段的value并非全为String类型——API返回的record可能包含数字、布尔值、嵌套JSON对象/数组等非String类型,而你声明的Map<String, String?>要求value必须是String,Moshi无法自动完成跨类型转换,因此抛出异常。

由于record对应上百种类型,无法逐个实现多态适配器,自定义JsonAdapter是最优解:通过适配器统一将record的所有类型值转换为String(或null)。


步骤1:自定义JsonAdapter

编写适配器类,处理JSON中所有可能的value类型,将其转换为String表示:

class ObjectToStringMapAdapter : JsonAdapter<Map<String, String?>>() {
    override fun fromJson(reader: JsonReader): Map<String, String?> {
        val resultMap = mutableMapOf<String, String?>()
        reader.beginObject()
        
        while (reader.hasNext()) {
            val key = reader.nextName()
            val value = when (reader.peek()) {
                JsonReader.Token.NULL -> {
                    reader.nextNull()
                    null
                }
                JsonReader.Token.BOOLEAN -> reader.nextBoolean().toString()
                JsonReader.Token.NUMBER -> reader.nextString() // 直接读取数字的字符串形式
                JsonReader.Token.STRING -> reader.nextString()
                JsonReader.Token.BEGIN_OBJECT, JsonReader.Token.BEGIN_ARRAY -> {
                    // 嵌套对象/数组转为JSON字符串保存
                    reader.readJsonValue().toString()
                }
                else -> {
                    reader.skipValue() // 跳过未知类型,也可返回null或自定义默认值
                    null
                }
            }
            resultMap[key] = value
        }
        
        reader.endObject()
        return resultMap
    }

    override fun toJson(writer: JsonWriter, value: Map<String, String?>?) {
        if (value == null) {
            writer.nullValue()
            return
        }
        writer.beginObject()
        value.forEach { (key, v) ->
            writer.name(key)
            v?.let(writer::value) ?: writer.nullValue()
        }
        writer.endObject()
    }
}

步骤2:在数据类中绑定适配器

在record字段上添加@JsonAdapter注解,指定使用自定义适配器:

data class ApiResponse(
    val records: List<RecordEntry>
)

data class RecordEntry(
    @JsonAdapter(ObjectToStringMapAdapter::class)
    val record: Map<String, String?>
)

步骤3:正常解析API响应

创建Moshi实例并解析即可,无需额外配置:

val moshi = Moshi.Builder().build()
val adapter = moshi.adapter(ApiResponse::class.java)
val apiResponse = adapter.fromJson(jsonString)

自定义调整说明

如果不需要保留嵌套对象/数组的内容,可以修改适配器逻辑:

  • 遇到BEGIN_OBJECT或BEGIN_ARRAY时,直接调用reader.skipValue()并返回null
  • 或根据业务需求返回固定字符串(如"[object]")

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 07:32:46