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

Retrofit如何处理数组格式响应?多端点适配问题求助

解决Retrofit同时适配标准JSON与嵌套数组格式的问题

问题原因

你遇到的错误是因为Gson默认无法将[[String, Int]]这种嵌套数组结构直接映射到Array<Pair<String, Int>>:Gson没有内置Pair类型的反序列化规则,它会把每个子数组当成一个对象尝试解析,因此抛出Expected BEGIN_OBJECT but was BEGIN_ARRAY的异常。

解决方案:自定义Gson TypeAdapter

不需要替换整个ConverterFactory,只需扩展Gson的解析规则,让它能处理这种特殊的数组结构,同时不影响原有标准JSON接口的解析。

方法1:为Pair类型自定义TypeAdapter

  1. 编写Pair<String, Int>的TypeAdapter,处理嵌套数组的读写:
class StringIntPairAdapter : TypeAdapter<Pair<String, Int>>() {
    override fun write(out: JsonWriter, value: Pair<String, Int>) {
        out.beginArray()
        out.value(value.first)
        out.value(value.second)
        out.endArray()
    }

    override fun read(`in`: JsonReader): Pair<String, Int> {
        `in`.beginArray()
        val name = `in`.nextString()
        val id = `in`.nextInt()
        `in`.endArray()
        return Pair(name, id)
    }
}
  1. 修改APIModule中的Gson配置,注册这个TypeAdapter:
@InstallIn(SingletonComponent::class)
@Module
class APIModule {

    @Singleton
    @Provides
    @Named("default")
    fun provideDefaultOkHttpClient(): OkHttpClient =
        OkHttpClient
            .Builder()
            .addInterceptor(HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY))
            .build()

    @Singleton
    @Provides
    fun provideGson(): Gson = GsonBuilder()
        .registerTypeAdapter(Pair::class.java, StringIntPairAdapter())
        .create()

    @Singleton
    @Provides
    fun provideRetrofit(
        @Named("default") okHttpClient: OkHttpClient,
        gson: Gson
    ): Retrofit = Retrofit.Builder()
        .addConverterFactory(GsonConverterFactory.create(gson))
        .baseUrl("https://test.com")
        .client(okHttpClient)
        .build()
}

这样修改后,/api/products的标准JSON解析不受影响,/api/type返回的嵌套数组会被自动转换成Array<Pair<String, Int>>。

方法2:使用自定义数据类(推荐)

用自定义数据类替代Pair,可读性更强,也能避免泛型带来的潜在问题:

  1. 定义数据类:
data class TypeItem(val modelName: String, val modelId: Int)
  1. 编写对应TypeAdapter:
class TypeItemAdapter : TypeAdapter<TypeItem>() {
    override fun write(out: JsonWriter, value: TypeItem) {
        out.beginArray()
        out.value(value.modelName)
        out.value(value.modelId)
        out.endArray()
    }

    override fun read(`in`: JsonReader): TypeItem {
        `in`.beginArray()
        val name = `in`.nextString()
        val id = `in`.nextInt()
        `in`.endArray()
        return TypeItem(name, id)
    }
}
  1. 更新Gson配置和Service接口:
// 在provideGson中注册TypeAdapter
.registerTypeAdapter(TypeItem::class.java, TypeItemAdapter())

// Service接口修改为
@GET("api/type")
suspend fun getType(): List<TypeItem>

补充说明

不存在能自动适配所有JSON和数组格式的通用ConverterFactory,但通过Gson的TypeAdapter扩展机制,我们可以精准地为特殊格式的接口添加解析规则,同时保留原有标准JSON的解析能力,这是最灵活且低成本的解决方案。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 14:17:05