Gson转换JSON报错:Expected a string but was BEGIN_OBJECT 求助
问题
调用第三方API获取JSON数据时,System.out.println(jsonCep.toString())能正常打印JSON结构,但执行UsuarioPessoa user = new Gson().fromJson(jsonCep.toString(), UsuarioPessoa.class);时,Gson抛出错误:Expected a string but was BEGIN_OBJECT。
打印出的JSON内容
{"status":{"code":200,"message":"Ok"},"data":[],"page":{"next":"https://sandbox-api.arquivei.com.br/v1/nfe/received?cnpj%5C%5B0%5C%5D=34174654000153&cursor=0&limit=50%22,%22previous%22:%22https://sandbox-api.arquivei.com.br/v1/nfe/received?cnpj%5C%5B0%5C%5D=34174654000153&cursor=0&limit=50%22%7D,%22count%22:0,%22signature%22:%224f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945"}
完整代码
public void pesquisaCode() { try { String code="34174654000153"; String apikey = "69087091f4d28d29e5c2d326831c86bfc7903634"; String apiID="b79cbfedaf0d9b0be1a3a2d7263fdc61c94e2311"; URL url = new URL("https://sandbox-api.arquivei.com.br/v1/nfe/received?cnpj[]="+code+""); URLConnection connection = url.openConnection(); connection.setRequestProperty("Content-Type","application/json"); connection.setRequestProperty("X-API-KEY", apikey); connection.setRequestProperty("X-API-ID", apiID); ((HttpURLConnection) connection).setRequestMethod("GET"); connection.setDoOutput(true); InputStream is = connection.getInputStream(); BufferedReader br = new BufferedReader(new InputStreamReader(is, "UTF-8")); String cep=""; StringBuilder jsonCep = new StringBuilder(); while((cep = br.readLine()) != null) { jsonCep.append(cep); } System.out.println(jsonCep.toString()); UsuarioPessoa user = new Gson().fromJson(jsonCep.toString(), UsuarioPessoa.class); } catch (Exception e) { e.printStackTrace(); } }
API返回的标准JSON(Postman中结果)
{ "status": { "code": 200, "message": "Ok" }, "data": [ ], "page": { "next": "https:\/\/sandbox-api.arquivei.com.br\/v1\/nfe\/received?cnpj[0]=34174654000153&cursor=0&limit=50", "previous": "https:\/\/sandbox-api.arquivei.com.br\/v1\/nfe\/received?cnpj[0]=34174654000153&cursor=0&limit=50" }, "count": 0, "signature": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945" }
解决方案
1. 修复JSON格式损坏问题
对比打印的JSON和Postman返回的标准JSON,能发现打印的JSON存在结构损坏:page字段的next值错误包含了后续的","previous":"..."等内容,导致整个JSON语法混乱,Gson无法正常解析。
问题根源是手动拼接URL时,cnpj[]参数未正确编码,服务器返回了格式错误的JSON。修复方式如下:
// 使用URLEncoder对参数进行正确编码 String encodedCode = URLEncoder.encode(code, "UTF-8"); URL url = new URL("https://sandbox-api.arquivei.com.br/v1/nfe/received?cnpj[]=" + encodedCode);
或者用更规范的URL构建方式(需引入Java EE的javax.ws.rs-api包):
URI uri = new UriBuilder() .scheme("https") .host("sandbox-api.arquivei.com.br") .path("/v1/nfe/received") .queryParam("cnpj[]", code) .build(); URL url = uri.toURL();
2. 匹配实体类与JSON结构
Gson抛出Expected a string but was BEGIN_OBJECT的核心原因是UsuarioPessoa类的字段定义与JSON结构不匹配。比如JSON中status是嵌套对象,但如果你的实体类将status定义为String类型,就会触发该错误。
需根据API返回的JSON结构,定义正确的实体类:
// 顶层实体类,对应整个JSON结构 public class ApiResponse { private Status status; private List<Object> data; // 若data有具体结构,替换为对应实体类 private Page page; private int count; private String signature; // 嵌套的Status类 public static class Status { private int code; private String message; // getter、setter、无参构造方法 } // 嵌套的Page类 public static class Page { private String next; private String previous; // getter、setter、无参构造方法 } // 顶层类的getter、setter、无参构造方法 }
之后用该类进行解析:
ApiResponse response = new Gson().fromJson(jsonCep.toString(), ApiResponse.class);
3. 优化HTTP请求处理
手动使用URLConnection易出现编码、流处理等问题,建议使用成熟的HTTP客户端库(如OkHttp)简化请求:
OkHttpClient client = new OkHttpClient(); Request request = new Request.Builder() .url("https://sandbox-api.arquivei.com.br/v1/nfe/received?cnpj[]=" + code) .addHeader("Content-Type", "application/json") .addHeader("X-API-KEY", apikey) .addHeader("X-API-ID", apiID) .build(); try (Response response = client.newCall(request).execute()) { String json = response.body().string(); ApiResponse apiResponse = new Gson().fromJson(json, ApiResponse.class); } catch (IOException e) { e.printStackTrace(); }
内容的提问来源于stack exchange,提问作者Lucas Baur
相关产品推荐
相关产品推荐

