You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot中RestTemplate无法将嵌套JSON转换为POJO报错

问题根因

报错核心原因是第三方接口返回的JSON顶层为对象结构(以{起始,对应错误提示中的JsonToken.START_OBJECT),但代码中直接指定反序列化目标类型为List<BitPayRates>——该类型对应JSON数组结构(以[起始),Jackson反序列化时结构匹配失败直接抛出异常。
结合你提到的接口返回多层嵌套JSON的前提,你需要的新闻列表数据并不在JSON最外层,而是存储在顶层对象的某个子属性中,直接将整个响应转换为List必然失败。

解决方案

按以下步骤调整即可:

  • 第一步:先定位目标数据的JSON层级
    单独调用一次第三方接口获取完整响应样例,找到存储新闻数组的具体层级路径,典型的接口返回结构参考如下:
    {
      "code": 200,
      "result": {
        "count": 87,
        "items": [
          {"news_id": 1, "news_provider_name": "CoinDesk", "HEADLINE": "xxx", "news_link": "xxx", "related_image": "xxx"}
        ]
      }
    }
    
    上述样例中目标新闻列表存储在result.items路径下,并非顶层节点。
  • 第二步:编写JSON响应对应的层级包装类
    不要直接用数据库实体类接收整个接口响应,按照定位到的JSON结构编写对应层级的包装类,所有包装类都添加@JsonIgnoreProperties(ignoreUnknown = true)注解自动忽略不需要的字段:
    // 顶层响应对象
    @JsonIgnoreProperties(ignoreUnknown = true)
    public class ThirdPartyNewsResponse {
        // 按实际JSON的顶层字段定义,比如样例中的code、result
        private Integer code;
        private ResultNode result;
        // 补全对应getter、setter
    }
    
    // 第二层result节点
    @JsonIgnoreProperties(ignoreUnknown = true)
    public class ResultNode {
        private Integer count;
        // 如果JSON字段名和Java属性名不一致,用@JsonProperty指定映射关系
        @JsonProperty("items")
        private List<BitPayRates> newsItems;
        // 补全对应getter、setter
    }
    
    如果JSON嵌套层级更深,按照相同逻辑逐层定义节点类即可,不需要的字段直接不定义,注解会自动跳过解析。
  • 第三步:调整RestTemplate的反序列化与入库逻辑
    修改exchange方法的响应类型为自定义的顶层包装类,拿到响应后逐层取出目标新闻列表,判空后再调用JPA方法批量入库:
    // 原错误写法:响应类型指定为ParameterizedTypeReference<List<BitPayRates>>
    ResponseEntity<ThirdPartyNewsResponse> response = restTemplate.exchange(
            apiUrl,
            HttpMethod.GET,
            buildAuthHeaderEntity(), // 之前定义的带X-RapidAPI-Key请求头的HttpEntity
            ThirdPartyNewsResponse.class
    );
    // 逐层取出新闻列表
    ThirdPartyNewsResponse body = response.getBody();
    if (body != null && body.getResult() != null) {
        List<BitPayRates> newsList = body.getResult().getNewsItems();
        if (newsList != null && !newsList.isEmpty()) {
            bitPayRatesRepository.saveAll(newsList);
        }
    }
    
快速调试方案

如果暂时不想编写多层包装类,可以先用Jackson的树模型JsonNode接收响应,手动定位到目标数组节点后再转换为实体列表,适合快速验证逻辑:

ResponseEntity<JsonNode> response = restTemplate.exchange(
        apiUrl,
        HttpMethod.GET,
        buildAuthHeaderEntity(),
        JsonNode.class
);
// 按实际层级路径定位数组节点,比如样例中的result -> items
JsonNode newsArrayNode = response.getBody().path("result").path("items");
// 转换为实体列表
ObjectMapper objectMapper = new ObjectMapper();
List<BitPayRates> newsList = objectMapper.convertValue(newsArrayNode, new ParameterizedTypeReference<List<BitPayRates>>() {});
// 后续入库逻辑不变

补充注意:如果接口返回的字段名和BitPayRates实体类的属性名不一致(比如接口返回headline全小写,实体写的是HEADLINE),需要在对应实体字段上添加@JsonProperty("接口实际字段名")做映射,否则会出现字段取值为空的问题。

内容的提问来源于stack exchange,提问作者Alex_Pap

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 15:51:19