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
相关产品推荐
相关产品推荐

