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
- 编写
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) } }
- 修改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,可读性更强,也能避免泛型带来的潜在问题:
- 定义数据类:
data class TypeItem(val modelName: String, val modelId: Int)
- 编写对应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) } }
- 更新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
相关产品推荐
相关产品推荐

