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

API返回对象/数组时,如何正确转换为Kotlin数据类?

解决API返回对象/数组兼容的Kotlin JSON解析问题

针对你遇到的API返回字段(supplements)有时是单个对象、有时是空数组的情况,核心思路是统一两种格式为同一种数据类型(推荐用列表),通过自定义JSON反序列化器来处理格式差异,以下是具体实现方案:

1. 定义目标数据类

首先明确supplements对应的实体类(比如Supplement),并修改ProductInfo的supplements字段为列表类型:

// 假设这是supplements对应的实体类,根据实际返回字段调整
data class Supplement(
    val id: String,
    val name: String
    // 其他字段根据API返回补充
)

// 修改后的ProductInfo
data class ProductInfo(
    var product: Product?,
    var specifications: JsonObject?,
    var supplements: List<Supplement>?, // 改为List类型,统一处理对象/数组
    var files: List<File>?,
    var feedback: Feedback?
)

2. 用Gson实现自定义反序列化

如果项目使用Gson作为JSON解析库,编写自定义反序列化器来兼容两种格式:

class SupplementsDeserializer : JsonDeserializer<List<Supplement>> {
    override fun deserialize(
        json: JsonElement?,
        typeOfT: Type?,
        context: JsonDeserializationContext?
    ): List<Supplement>? {
        return when {
            json == null || json.isJsonNull -> null
            // 处理数组:空数组返回空列表,非空则解析为列表
            json.isJsonArray -> {
                val array = json.asJsonArray
                if (array.isEmpty()) emptyList() else context?.deserialize(array, object : TypeToken<List<Supplement>>() {}.type)
            }
            // 处理单个对象:转为包含该对象的单元素列表
            json.isJsonObject -> {
                context?.deserialize(json, Supplement::class.java)?.let { listOf(it) } ?: emptyList()
            }
            else -> null
        }
    }
}

注册反序列化器并使用:

// 初始化带自定义解析器的Gson实例
val gson = GsonBuilder()
    .registerTypeAdapter(object : TypeToken<List<Supplement>>() {}.type, SupplementsDeserializer())
    .create()

// 解析JSON字符串
val productInfo = gson.fromJson(yourJsonString, ProductInfo::class.java)

3. 用Moshi实现自定义反序列化

如果项目使用Moshi,编写对应的JSON适配器:

class SupplementsJsonAdapter(private val itemAdapter: JsonAdapter<Supplement>) : JsonAdapter<List<Supplement>>() {
    override fun fromJson(reader: JsonReader): List<Supplement>? {
        return when (reader.peek()) {
            JsonReader.Token.NULL -> {
                reader.nextNull()
                null
            }
            // 处理数组:遍历解析每个元素
            JsonReader.Token.BEGIN_ARRAY -> {
                val list = mutableListOf<Supplement>()
                reader.beginArray()
                while (reader.hasNext()) {
                    itemAdapter.fromJson(reader)?.let { list.add(it) }
                }
                reader.endArray()
                list.takeIf { it.isNotEmpty() } ?: emptyList()
            }
            // 处理单个对象:转为单元素列表
            JsonReader.Token.BEGIN_OBJECT -> {
                itemAdapter.fromJson(reader)?.let { listOf(it) } ?: emptyList()
            }
            else -> {
                reader.skipValue()
                emptyList()
            }
        }
    }

    // 序列化时可选:将列表转为单个对象(如果只有一个元素)或数组
    override fun toJson(writer: JsonWriter, value: List<Supplement>?) {
        if (value == null) {
            writer.nullValue()
            return
        }
        if (value.size == 1) {
            itemAdapter.toJson(writer, value.first())
        } else {
            writer.beginArray()
            value.forEach { itemAdapter.toJson(writer, it) }
            writer.endArray()
        }
    }
}

注册适配器并使用:

// 初始化带自定义适配器的Moshi实例
val moshi = Moshi.Builder()
    .add(SupplementsJsonAdapter(Moshi.Builder().build().adapter(Supplement::class.java)))
    .build()

// 解析JSON字符串
val productInfoAdapter = moshi.adapter(ProductInfo::class.java)
val productInfo = productInfoAdapter.fromJson(yourJsonString)

核心逻辑说明

自定义解析器的作用是在JSON解析时自动判断字段类型:

  • 若返回单个对象,将其包装为单元素列表
  • 若返回数组,直接解析为列表(空数组返回空列表)
  • 业务代码中只需处理List<Supplement>?,无需再判断原数据格式

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 10:30:42