JSON 解析错误:无法反序列化 START_ARRAY 令牌中的实例

Posted

技术标签:

【中文标题】JSON 解析错误:无法反序列化 START_ARRAY 令牌中的实例【英文标题】:JSON parse error: Cannot deserialize instance of `` out of START_ARRAY token 【发布时间】:2020-04-03 08:44:54 【问题描述】:

我是 Spring Boot 和 API 的新手,我正在开发一个项目,我需要从公共 API 获取数据并将其存储到本地数据库,尽管我的 Spring Boot 应用程序与 mysql 数据库连接。从 API 获取数据时,我的编译器抛出异常:

Error while extracting response for type [class com.currencyExchangeRates.models.CurrencyDTO] and content type [application/json;charset=utf-8]; nested exception is org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot deserialize instance of `com.currencyExchangeRates.models.CurrencyDTO` out of START_ARRAY token; nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of `com.currencyExchangeRates.models.CurrencyDTO` out of START_ARRAY token at [Source: (PushbackInputStream); line: 1, column: 1]

我的总体思路是从公共 API 获取数据,将其存储在本地数据库中,然后根据我的项目要求使用这些数据。

我已经尝试了几乎所有来自 google 和 *** 的解决方案,但我没有任何想法。

我正在尝试获取的 JSON 格式:

[
   
      "table":"A",
      "no":"237/A/NBP/2019",
      "effectiveDate":"2019-12-09",
      "rates":[
         
            "currency":"bat (Tajlandia)",
            "code":"THB",
            "mid":0.1277
         ,
         
            "currency":"dolar amerykański",
            "code":"USD",
            "mid":3.8704
         
      ]
   
]

这里,我的 CurrencyDTO 类:

public class CurrencyDTO 

    private String table;
    private String num;
    private String date;

    private Rates rates;

    // Getters and Setters, No-arg/arg constractor

Rates.java

public class Rates 

    private String currency;
    private Map<String, Double> price;

    // Getters and Setters, No-arg/arg constractor

我调用 API 的一段代码:

try 
            RestTemplate restTemplate = new RestTemplate();

            CurrencyDTO forObject = 
                    restTemplate.getForObject("http://api.nbp.pl/api/exchangerates/tables/a/", CurrencyDTO.class);

                forObject.getRates().getPrice().forEach((key, value) -> 
                Currency currency = new Currency(key, value);
                this.currencyRepository.save(currency); 
            );
        catch (RestClientException ex) 
            System.out.println(ex.getMessage());
        

控制器类:

@GetMapping("/currency")
    public List<Currency> findAll()
        return currencyService.getAllCurrencies();
    

【问题讨论】:

【参考方案1】:

此外,您共享的 json 是 CurrencyDTO 数组。假设你的 Json 是,

  
      "table":"A",
      "no":"237/A/NBP/2019",
      "effectiveDate":"2019-12-09",
      "rates":[
         
            "currency":"bat (Tajlandia)",
            "code":"THB",
            "mid":0.1277
         ,
         
            "currency":"dolar amerykański",
            "code":"USD",
            "mid":3.8704
         
      ]
   

将您的 CurrencyDTO 更改为,

@Data
@NoArgsConstructor
public class CurrencyDTO 

    private String table;
    private String no;
    private String effectiveDate;

    private List<Rates> rates;

和你的 Rates 类,

@Data
@NoArgsConstructor
public class Rates 

    private String currency;
    private String code;
    private Double mid;

它能够为我反序列化。 您做错的是 Dto 实例变量应该根据 Json 中的名称,或者您应该使用 @JsonProperty("nameInTheJson")

如果你想让它与你的 JSON 兼容,你可以使用 Array of CurrencyDTO 您将能够反序列化,您可以将对象用作,

try 
       RestTemplate restTemplate = new RestTemplate();

       CurrencyDTO[] forObject =
                    restTemplate.getForEntity("http://api.nbp.pl/api/exchangerates/tables/a/", CurrencyDTO[].class).getBody();
          for (CurrencyDTO currencyDTO1 : forObject) 
                for (Rates rate : currencyDTO1.getRates()) 
                    Currency currency = new Currency(rate.getCode(), rate.getMid());
                    //you code to put the object inside the db
                    this.currencyRepository.save(currency);
                
            
        catch (Exception ex) 
            System.out.println(ex.getMessage());
        

【讨论】:

【参考方案2】:

首先,您的 JSON 是 CurrencyDTO 数组,而不仅仅是评论中提到的 CurrencyDTO,现在如果它影响代码的其他部分并且您只想按原样反序列化它,那么您可以执行以下操作:

CurrencyDTO[] forObject = new ObjectMapper.readValue(restTemplate.getForEntity("http://api.nbp.pl/api/exchangerates/tables/a/", CurrencyDTO[].class).getBody() , new TypeReference<List<CurrencyDTO>>() ).get(0);

另外,我强烈建议这是你应该做的最糟糕的方式。最好更新您的 API 以返回正确的响应。

【讨论】:

以上是关于JSON 解析错误:无法反序列化 START_ARRAY 令牌中的实例的主要内容,如果未能解决你的问题,请参考以下文章

JSON 解析错误:无法反序列化 START_ARRAY 令牌中的实例

JSON 解析错误:无法从 START_OBJECT 令牌中反序列化 java.util.ArrayList 的实例

C#解析json时,总出现反序列化失败是啥原因解决方案

反序列化 Json 出现错误“无法反序列化当前 JSON 数组”

Json 映射异常无法从 START_ARRAY 令牌中反序列化实例

错误:预期状态。无法反序列化 JSON 对象