Gson反序列化报错:Expected BEGIN_OBJECT but was STRING求助
问题排查与解决:Gson反序列化异常
异常原因
异常java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING at line 1 column 67 path $.data明确指向:接口返回的JSON中,data字段的值是字符串类型,但你的CheckTokenResp类里将data定义为CmsUser对象类型,Gson无法将字符串直接反序列化为对象,因此抛出错误。
排查步骤
先打印接口返回的完整JSON内容,确认data字段的实际格式:
log.info("接口返回原始JSON: {}", responseEntity.getBody());
大概率会看到类似这样的结构(data是包裹JSON的字符串):
{ "code": 200, "message": "success", "data": "{\"id\":123,\"username\":\"test\",\"role\":\"admin\"}" }
解决方案
根据data字段的实际内容,有两种常见处理方式:
方式一:修改CheckTokenResp适配返回结构
将CheckTokenResp中的data字段类型改为String,再二次反序列化为CmsUser:
- 调整
CheckTokenResp类:public class CheckTokenResp { // 保留其他原有字段(如code、message等) private String data; // 替换原有的CmsUser类型 // 生成getter、setter方法 } - 修改业务代码:
Gson gson = new Gson(); CheckTokenResp response = gson.fromJson(responseEntity.getBody(), CheckTokenResp.class); if (response == null || response.getData() == null) { return null; } // 将字符串类型的data反序列化为CmsUser对象 CmsUser cmsUser; try { cmsUser = gson.fromJson(response.getData(), CmsUser.class); } catch (JsonSyntaxException e) { log.warn("data字段无法反序列化为CmsUser: {}", response.getData(), e); return null; } return cmsUser;
方式二:自定义Gson反序列化器(无需修改实体类)
如果不想修改CheckTokenResp的data字段类型,可以给Gson注册自定义类型适配器,自动处理字符串转对象的逻辑:
// 创建带自定义适配器的Gson实例 Gson gson = new GsonBuilder() .registerTypeAdapter(CmsUser.class, new TypeAdapter<CmsUser>() { @Override public void write(JsonWriter out, CmsUser value) throws IOException { // 序列化时的逻辑,按需实现 out.value(new Gson().toJson(value)); } @Override public CmsUser read(JsonReader in) throws IOException { // 反序列化时,判断当前token是字符串还是对象 if (in.peek() == JsonToken.STRING) { // 若为字符串,先读取再反序列化为CmsUser String jsonStr = in.nextString(); return new Gson().fromJson(jsonStr, CmsUser.class); } else { // 若为对象,直接反序列化 return new Gson().fromJson(in, CmsUser.class); } } }) .create(); // 后续反序列化代码保持不变 CheckTokenResp response = gson.fromJson(responseEntity.getBody(), CheckTokenResp.class);
额外优化建议
- 避免捕获
Exception这种宽泛的异常,改为捕获RestClientException,精准处理HTTP请求异常; - 增加
responseEntity的非空判断,避免请求失败时调用responseEntity.getBody()抛出空指针; - 和后端确认接口返回规范,明确
data字段的类型是否会在不同场景下变化(比如错误时返回提示字符串),提前兼容这些场景。
内容的提问来源于stack exchange,提问作者Đức Hiếu Nguyễn
相关产品推荐
相关产品推荐

