Android Retrofit调用API报错:Expected BEGIN_OBJECT but was STRING at $.data
问题:Retrofit解析响应时出现IllegalStateException错误
1. API调用定义
@POST(ApiConstant.ADD_MEMBER) Call<MemberResponse> addMember(@Body Map<String, Object> map);
2. 请求调用代码
HashMap<String, Object> list = new HashMap<>(); list.put("code", TinyDB.getInstance().getString(PrefrenceConstent.TRAINER_CODE)); list.put("first_name", TinyDB.getInstance().getString(PrefrenceConstent.KEY_NAME)); list.put("email", TinyDB.getInstance().getString(PrefrenceConstent.KEY_USER_EMAIL)); list.put("contact", TinyDB.getInstance().getString(PrefrenceConstent.KEY_USER_MOBILE)); list.put("last_name", "Null"); try { Response<MemberResponse> responseAllInvites = ApiBuilder.getApiInterfaceCoachPro().addMember(list).execute(); if (responseAllInvites.body() != null) { Timber.e("Response: %s", responseAllInvites.body().getData()); MemberInfo invitationsList = responseAllInvites.body().getData(); String member_code = invitationsList.getMember_code(); Timber.e("Member Code: %s", member_code); } } catch (Exception e) { return Result.failure(); }
3. POJO类定义
public class MemberResponse { @SerializedName("data") @Expose private MemberInfo data; @SerializedName("Message") @Expose private String message; public MemberInfo getData() { return data; } public void setData(MemberInfo data) { this.data = data; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; }}
4. 预期响应JSON
{ "data": { "id": 84, "member_code": "testcrm-72807-47474-12" }, "Message": "Member details were successfully created!"}
5. 错误信息
java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING at line 1 column 10 path $.data
问题原因
错误提示明确说明:解析器期望$.data是一个对象(BEGIN_OBJECT对应JSON中的{}),但实际返回的是字符串类型。这意味着接口返回的真实JSON中,data字段并非你预期的对象结构,而是一段字符串(比如"data": "操作失败"这类格式),导致Gson无法将其解析为MemberInfo对象,抛出异常。
排查步骤
- 打印完整响应内容:在请求逻辑中添加代码,打印接口返回的完整响应(包括错误响应),确认
data字段的真实类型:try { Response<MemberResponse> responseAllInvites = ApiBuilder.getApiInterfaceCoachPro().addMember(list).execute(); // 打印完整响应内容(注意errorBody().string()只能调用一次) if (!responseAllInvites.isSuccessful() && responseAllInvites.errorBody() != null) { Timber.e("Error Response: %s", responseAllInvites.errorBody().string()); } else if (responseAllInvites.body() != null) { Timber.e("Full Response: %s", new Gson().toJson(responseAllInvites.body())); } // 原有业务逻辑... } catch (Exception e) { Timber.e(e); return Result.failure(); } - 确认接口返回规则:和后端开发人员确认,接口在不同场景下(比如参数错误、重复提交)的返回格式是否统一,是否存在
data字段类型切换的情况。
解决办法
方案1:协调后端统一响应格式
要求后端确保data字段始终为对象类型:
- 成功时返回预期的对象结构
- 失败时返回
null或空对象{},而非字符串
方案2:修改POJO适配动态类型
如果后端无法修改返回格式,调整MemberResponse的data字段类型,兼容对象和字符串两种情况:
import com.google.gson.JsonElement; public class MemberResponse { @SerializedName("data") @Expose private JsonElement data; @SerializedName("Message") @Expose private String message; public JsonElement getData() { return data; } public void setData(JsonElement data) { this.data = data; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } }
然后在解析时判断类型并处理:
if (responseAllInvites.body() != null) { JsonElement dataElement = responseAllInvites.body().getData(); if (dataElement.isJsonObject()) { // 解析为MemberInfo对象 MemberInfo invitationsList = new Gson().fromJson(dataElement, MemberInfo.class); String member_code = invitationsList.getMember_code(); Timber.e("Member Code: %s", member_code); } else if (dataElement.isJsonPrimitive()) { // 处理字符串类型的data String dataStr = dataElement.getAsString(); Timber.e("Data content: %s", dataStr); } }
内容的提问来源于stack exchange,提问作者Rohit Barge
相关产品推荐
相关产品推荐

