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

Android Kotlin Moshi:自定义适配器无法实现多字段映射

Moshi适配多JSON字段到同一类属性的实现方案

需求背景

需要将两组不同结构的JSON(包含单个字段和复杂对象结构)序列化/反序列化到同一个CollegeUS类,替代Gson中@SerializedName的alternate属性功能,且不使用反射型的KotlinJsonAdapterFactory,保证高效性。

实现步骤

1. 定义目标数据类

先确定CollegeUS的结构,包含所有需要映射的属性:

data class CollegeUS(
    val name: String,
    val stateProvince: String?,
    val country: String?,
    val page: String
)

2. 编写自定义JsonAdapter

通过手动遍历JSON字段的方式实现适配,完全避免反射,性能更优:

class CollegeUSAdapter {
    @FromJson
    fun fromJson(reader: JsonReader): CollegeUS {
        var name: String? = null
        var stateProvince: String? = null
        var country: String? = null
        var page: String? = null

        reader.beginObject()
        while (reader.hasNext()) {
            when (val fieldName = reader.nextName()) {
                // 处理name字段的所有备选key
                "school.name", "name", "college_name" -> name = reader.nextString()
                // 处理state字段的备选key
                "state-province", "state" -> stateProvince = reader.nextString()
                "country" -> country = reader.nextString()
                "page" -> page = reader.nextString()
                // 忽略未定义的字段,避免解析失败
                else -> reader.skipValue()
            }
        }
        reader.endObject()

        // 按需添加非空校验,确保核心字段存在
        checkNotNull(name) { "Missing required field: name (or its alternate keys)" }
        checkNotNull(page) { "Missing required field: page" }

        return CollegeUS(name, stateProvince, country, page)
    }

    @ToJson
    fun toJson(writer: JsonWriter, college: CollegeUS) {
        // 序列化时可统一输出格式,示例采用第二种复杂JSON的结构
        writer.beginObject()
        writer.name("college_name").value(college.name)
        college.stateProvince?.run { writer.name("state").value(this) }
        college.country?.run { writer.name("country").value(this) }
        writer.name("page").value(college.page)
        writer.endObject()
    }
}

3. 注册适配器并使用

将自定义适配器加入Moshi构建器,即可正常进行序列化/反序列化:

val moshi = Moshi.Builder()
    .add(CollegeUSAdapter())
    .build()

// 反序列化测试
val simpleJson1 = """{"school.name": "A school name", "page": "1"}"""
val college1 = moshi.adapter(CollegeUS::class.java).fromJson(simpleJson1)

val complexJson2 = """{
    "college_name": "Any college",
    "state": "Any state",
    "page": "1",
    "country": "Any country"
}"""
val college2 = moshi.adapter(CollegeUS::class.java).fromJson(complexJson2)

// 序列化测试
val testCollege = CollegeUS("Stanford", "California", "USA", "3")
val serializedJson = moshi.adapter(CollegeUS::class.java).toJson(testCollege)

方案说明

  • 完全覆盖Gson中alternate属性的功能,支持多个备选JSON字段映射到同一类属性
  • 手动编写适配器无需依赖反射,性能优于KotlinJsonAdapterFactory
  • 灵活控制序列化输出格式,可根据业务需求调整输出的JSON结构
  • 自动忽略未知字段,提升解析的兼容性和稳定性

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 02:00:14