Gson反序列化JSON转POJO时报Expected BEGIN_OBJECT错误如何解决?
问题根因
你遇到的报错是因为JSON结构和POJO定义的类型不匹配:
观察你提供的JSON,x-business-use-case-usage数组内的元素不是原生JSON对象,而是被转义处理的JSON字符串:
"x-business-use-case-usage": [ // 这里被引号包裹,属于字符串类型,不是JSON对象 "{\"692950841314120\":[{\"type\":\"ads_management\",\"call_count\":3,\"total_cputime\":1,\"total_time\":5,\"estimated_time_to_regain_access\":0}]}" ]
你在POJO中将该字段定义为List<UseCase>,Gson反序列化时预期读取对象起始标记{,实际读取到的是字符串起始标记",因此抛出Expected BEGIN_OBJECT but was STRING异常。
解决方法
提供两种常用方案,可按需选择:
方案1:两步反序列化(推荐,改动最小)
先将字段声明为字符串列表,取到嵌套的JSON字符串后再单独反序列化:
- 修改
JsonClass的字段类型:
@NoArgsConstructor @AllArgsConstructor @ToString @Getter @Setter public class JsonClass { @SerializedName("x-business-use-case-usage") // 先存字符串列表,不要直接声明为UseCase类型 private List<String> businessUseCaseStr; }
- 调整转换逻辑,新增二次反序列化步骤:
@SuppressWarnings("deprecation") JsonParser parser = new JsonParser(); Object obj = parser.parse(new FileReader("res.json")); JsonObject s = (JsonObject)obj; Gson gson = new Gson(); JsonClass header = gson.fromJson(s.toString(), JsonClass.class); // 取出嵌套的JSON字符串,单独反序列化为UseCase对象 String useCaseJson = header.getBusinessUseCaseStr().get(0); UseCase useCase = gson.fromJson(useCaseJson, UseCase.class); // 此时即可正常获取内部的Case列表 List<Case> caseList = useCase.getC();
方案2:自定义TypeAdapter(适合批量处理同类场景)
如果多处存在嵌套JSON字符串的场景,可以自定义TypeAdapter让Gson自动完成二次反序列化,无需每次手动处理:
- 实现针对嵌套JSON的TypeAdapter:
public class NestedJsonAdapter<T> extends TypeAdapter<T> { private final Gson gson = new Gson(); private final Class<T> clazz; public NestedJsonAdapter(Class<T> clazz) { this.clazz = clazz; } @Override public void write(JsonWriter out, T value) throws IOException { out.value(gson.toJson(value)); } @Override public T read(JsonReader in) throws IOException { // 先读字符串,再反序列化为目标类型 String jsonStr = in.nextString(); return gson.fromJson(jsonStr, clazz); } }
- 在
JsonClass的字段上指定使用该Adapter:
@NoArgsConstructor @AllArgsConstructor @ToString @Getter @Setter public class JsonClass { @SerializedName("x-business-use-case-usage") @JsonAdapter(NestedJsonAdapter.class) private List<UseCase> businessUseCase; }
之后就可以直接用原有的转换逻辑反序列化,不需要额外改动。
内容的提问来源于stack exchange,提问作者Xolo12er
相关产品推荐
相关产品推荐

