使用Retrofit和Gson调用API返回数组的数组而非对象数组问题
开发一个涉及API调用的项目,通过Postman确认API响应是对象数组,但使用Retrofit结合Gson调用时,出现Expected BEGIN_OBJECT but was BEGIN_ARRAY错误。将API响应类型修改为List<ProductResponse>排查后,发现返回的是多个ProductResponse实例组成的数组,但所有实例的products字段均为null,无法获取有效数据。
相关代码
创建API服务与身份验证配置
fun createApiService(): ApiService { val client = OkHttpClient.Builder() .addInterceptor( BasicAuthInterceptor( "username", "password" ) ) .build() val api = Retrofit.Builder() .baseUrl(BASE_URL) .client(client) .addConverterFactory(GsonConverterFactory.create()) .build() return api.create(ApiService::class.java) } class BasicAuthInterceptor(username: String, password: String) : Interceptor { private var credentials: String = Credentials.basic(username, password) override fun intercept(chain: Interceptor.Chain): okhttp3.Response { var request = chain.request() request = request.newBuilder().header("Authorization", credentials).build() return chain.proceed(request) } }
该代码用于创建API服务并传入用户名密码,目标API为私有接口,需身份验证。
数据类定义
data class ProductResponse( val products: List<Product> ) data class Product( // 产品属性定义在此 )
API接口定义
interface ApiService { @GET("products") suspend fun getAllProducts(): List<ProductResponse> }
仓库实现类
class ProductRepositoryImpl( private val apiService: ApiService, ) : ProductRepository { override suspend fun getProducts(isInternetConnected: Boolean): List<Product> { val dataFromServer = apiService.getAllProducts() Log.v("api",dataFromServer.toString()) return dataFromServer[0].products } }
日志输出
[ProductResponse(products=null), ProductResponse(products=null), ProductResponse(products=null), ProductResponse(products=null), ProductResponse(products=null), ProductResponse(products=null), ProductResponse(products=null), ProductResponse(products=null), ProductResponse(products=null), ProductResponse(products=null)]
Postman响应示例
[{ "name": "test", "type": "simple", "featured": false, "catalog_visibility": "visible", "description": "", "short_description": "", "price": "351000", "regular_price": "351000", "sale_price": "", "on_sale": false, "purchasable": true, "total_sales": 0, "button_text": "", "tax_status": "taxable", "tax_class": "", "manage_stock": false, "stock_quantity": null, "backorders": "no", "backorders_allowed": false, "backordered": false, "low_stock_amount": null, "sold_individually": false, "weight": "", "shipping_required": true, "shipping_taxable": true, "shipping_class": "", "shipping_class_id": 0, "reviews_allowed": true, "average_rating": "0.00", "rating_count": 0, "parent_id": 0, "purchase_note": "", // 后续内容省略,总长度超过600行 }]
解决方案
问题核心是数据类结构与API实际响应不匹配:Postman返回的是直接由Product对象组成的数组,而非包含products字段的ProductResponse数组,多余的ProductResponse导致Gson无法匹配字段,最终赋值为null。
修改步骤:
- 调整API接口返回类型
interface ApiService { @GET("products") suspend fun getAllProducts(): List<Product> }
- 删除多余的
ProductResponse数据类,并补全Product类的字段,确保与API返回属性一一对应
data class Product( val name: String, val type: String, val featured: Boolean, val catalog_visibility: String, val description: String, val short_description: String, val price: String, val regular_price: String, // 补充API返回的其他所有属性 )
- 修改仓库实现逻辑
class ProductRepositoryImpl( private val apiService: ApiService, ) : ProductRepository { override suspend fun getProducts(isInternetConnected: Boolean): List<Product> { val dataFromServer = apiService.getAllProducts() Log.v("api",dataFromServer.toString()) return dataFromServer } }
修改后Gson可正确解析API返回的对象数组,不会再出现字段为null的情况。
内容的提问来源于stack exchange,提问作者nima

