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

如何解析多类型API JSON响应并在Kotlin中创建对应数据模型?

Kotlin兼容多类型API响应的数据模型方案

问题背景

调用同一API时,携带不同参数会返回两种格式的JSON响应:

  • 非空的对象集合(注:示例格式不符合标准JSON规范,缺少外层数组包裹):
{
  "name": "my name",
  "family": "my family"
},
{
  "name": "my name1",
  "family": "my family1"
}
  • 空数组:
[]

解决方案

1. 基础数据类定义

先定义单个数据项的模型:

data class Person(
    val name: String,
    val family: String
)

2. 针对Gson的处理

如果API返回的非空响应是无外层数组的多个对象(如示例),需要自定义TypeAdapter兼容数组和零散对象两种格式;如果是标准数组格式(外层有[]),直接用List<Person>接收即可。

自定义适配器代码:

class PersonListTypeAdapter : TypeAdapter<List<Person>>() {
    private val personAdapter = Gson().getAdapter(Person::class.java)

    override fun write(out: JsonWriter, value: List<Person>?) {
        out.beginArray()
        value?.forEach { personAdapter.write(out, it) }
        out.endArray()
    }

    override fun read(`in`: JsonReader): List<Person> {
        val result = mutableListOf<Person>()
        when (`in`.peek()) {
            JsonToken.BEGIN_ARRAY -> {
                `in`.beginArray()
                while (`in`.hasNext()) {
                    result.add(personAdapter.read(`in`))
                }
                `in`.endArray()
            }
            JsonToken.BEGIN_OBJECT -> {
                do {
                    result.add(personAdapter.read(`in`))
                } while (`in`.peek() != JsonToken.END_DOCUMENT)
            }
        }
        return result
    }
}

注册并使用:

val gson = GsonBuilder()
    .registerTypeAdapter(List::class.java, PersonListTypeAdapter())
    .create()

val personList = gson.fromJson(responseBody, object : TypeToken<List<Person>>() {}.type)

3. 针对Moshi的处理

通过自定义JsonAdapter实现格式兼容:

class PersonListAdapter {
    @FromJson
    fun fromJson(reader: JsonReader, delegate: JsonAdapter<Person>): List<Person> {
        val result = mutableListOf<Person>()
        when (reader.peek()) {
            JsonReader.Token.BEGIN_ARRAY -> {
                reader.beginArray()
                while (reader.hasNext()) {
                    delegate.fromJson(reader)?.let { result.add(it) }
                }
                reader.endArray()
            }
            JsonReader.Token.BEGIN_OBJECT -> {
                do {
                    delegate.fromJson(reader)?.let { result.add(it) }
                } while (reader.peek() != JsonReader.Token.END_DOCUMENT)
            }
        }
        return result
    }

    @ToJson
    fun toJson(writer: JsonWriter, value: List<Person>?, delegate: JsonAdapter<Person>) {
        writer.beginArray()
        value?.forEach { delegate.toJson(writer, it) }
        writer.endArray()
    }
}

注册并使用:

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

val listAdapter = moshi.adapter<List<Person>>(Types.newParameterizedType(List::class.java, Person::class.java))
val personList = listAdapter.fromJson(responseBody)

补充提示

如果API返回的非空响应是标准JSON数组(外层包含[]),无需自定义适配器,直接用List<Person>作为解析类型即可,Gson和Moshi都能自动处理空数组和非空数组的情况。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 20:36:27