Kotlin中Retrofit+Gson解析JSON报错:Expected a string but was BEGIN_ARRAY
问题:Retrofit解析JSON时抛出
Expected a string but was BEGIN_ARRAY异常 问题详情
我是JSON解析新手,使用Square的Retrofit库时遇到了解析问题。
API返回的JSON响应(示例):
[{ "contactName":"ABC", "addons":[ {"vasCode":"GTG021","propCode":"PROP0044","propValue":"0","fieldName":null}, {"vasCode":"GTG021","propCode":"PROP0043","propValue":"175000","fieldName":null}, {"vasCode":"GTG021","propCode":"PROP0018","propValue":"175000","fieldName":"COD_AMOUNT"}, {"vasCode":"GTG021","propCode":"PROP0019","propValue":"1","fieldName":"PAID_TYPE_COD"}, {"vasCode":"GTG021","propCode":"PROP0022","propValue":null,"fieldName":"BRANCH_NAME"}, {"vasCode":"GTG021","propCode":"PROP0021","propValue":null,"fieldName":"BANK_NAME"}, {"vasCode":"GTG021","propCode":"PROP0020","propValue":null,"fieldName":"ACCOUNT_NUMBER_COD"}], "packages":"250000" }]
定义的Kotlin数据类:
data class Contacts { @SerializedName("contactName") var contactName: String, @SerializedName("addons") var addons: ArrayList<Addons>, @SerializedName("packages") var packages: String, } data class Addons { @SerializedName("vasCode") var vasCode: String, @SerializedName("propCode") var propCode: String, @SerializedName("propValue") var propValue: String, @SerializedName("fieldName") var fieldName: String, }
Retrofit接口:
interface GetItemData { @GET("searchTtNumber?mode=API") fun getItem( @Header("authorization") authorization: String, @Query("ttNumber") ttNumber: String, @Query("orgCode") orgCode: String ): Call<ArrayList<Contacts>> }
Retrofit构建器:
object RetrofitHelperItem { fun getInstance(): Retrofit { return Retrofit.Builder() .baseUrl("https://something/") // Base URL of the API .addConverterFactory(ScalarsConverterFactory.create()) .addConverterFactory(GsonConverterFactory.create()) .build() } }
请求数据的类:
class ItemData(private val key : String,private val bien : String,private val orgCode : String) { // Create the ApiService instance using the Retrofit instance private val apiServiceItem = RetrofitHelperItem.getInstance().create(GetItemData::class.java) private var dt : ArrayList<Contacts>? = null suspend fun getItemData() : ArrayList<Contacts>? { try { val response = apiServiceItem.getItem(key, bien, orgCode).execute() if (response.isSuccessful) { dt = response.body() } } catch (e: Exception) { e.printStackTrace() } return dt } }
抛出的错误:
java.lang.IllegalStateException: Expected a string but was BEGIN_ARRAY at line 1 column 2075 path $[0].packages
解决方案
1. 核心问题定位
错误提示明确说明:解析$[0].packages字段时,代码期望得到字符串类型,但实际收到的是数组类型。这意味着你实际请求到的JSON中,packages字段并非示例里的字符串"250000",而是数组格式(比如["250000"])。
2. 修改数据类适配真实字段类型
将Contacts类中的packages字段类型从String改为List<String>。同时修复数据类的语法错误,并为可能为null的字段添加可空标记:
data class Contacts( @SerializedName("contactName") var contactName: String, @SerializedName("addons") var addons: ArrayList<Addons>, @SerializedName("packages") var packages: List<String> // 改为数组类型 ) data class Addons( @SerializedName("vasCode") var vasCode: String, @SerializedName("propCode") var propCode: String, @SerializedName("propValue") var propValue: String?, // 允许null @SerializedName("fieldName") var fieldName: String? // 允许null )
3. 优化协程使用方式
在挂起函数中调用execute()会阻塞线程,建议改用Retrofit的挂起函数版本:
- 修改接口为挂起函数,返回
Response<List<Contacts>>(推荐用List替代ArrayList)
interface GetItemData { @GET("searchTtNumber?mode=API") suspend fun getItem( @Header("authorization") authorization: String, @Query("ttNumber") ttNumber: String, @Query("orgCode") orgCode: String ): Response<List<Contacts>> }
- 更新请求类逻辑:
class ItemData(private val key : String,private val bien : String,private val orgCode : String) { private val apiServiceItem = RetrofitHelperItem.getInstance().create(GetItemData::class.java) suspend fun getItemData() : List<Contacts>? { return try { val response = apiServiceItem.getItem(key, bien, orgCode) if (response.isSuccessful) { response.body() } else { null } } catch (e: Exception) { e.printStackTrace() null } } }
4. 验证真实返回的JSON结构
如果不确定API返回的真实格式,可以临时通过ScalarsConverterFactory获取原始JSON字符串打印确认:
// 临时添加接口方法 interface GetItemData { @GET("searchTtNumber?mode=API") suspend fun getRawItem( @Header("authorization") authorization: String, @Query("ttNumber") ttNumber: String, @Query("orgCode") orgCode: String ): Response<String> } // 在请求类中调用打印 suspend fun getRawJson() { try { val response = apiServiceItem.getRawItem(key, bien, orgCode) if (response.isSuccessful) { println("Raw JSON: ${response.body()}") } } catch (e: Exception) { e.printStackTrace() } }
内容的提问来源于stack exchange,提问作者HaTr
相关产品推荐
相关产品推荐

