1

I am new to Spring Boot and APIs, I am working on a project where I need to fetch data from public API and store it to the local database, though my spring boot application is connected with MySQL database. While fetching the data from the API, my compiler is throwing an exception saying :

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]

My general idea is to get data from public API store it on the local database and then use those data according to my project requirements.

I have tried almost every solution from Google as well as from Stack Overflow but I am not getting any idea.

JSON format I am trying to fetch:

[
   {
      "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
         }
      ]
   }
]

Here, my CurrencyDTO class:

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

Piece of code where I call 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());
        }

Controller Class :

@GetMapping("/currency")
    public List<Currency> findAll(){
        return currencyService.getAllCurrencies();
    }
3
  • 3
    Your JSON is an array of CurrencyDTO, not just a CurrencyDTO Commented Dec 10, 2019 at 7:57
  • @D.Lawrence I have tried that as well, but that is affecting my code where I call API. Commented Dec 10, 2019 at 8:02
  • Share Currency class Commented Dec 13, 2019 at 10:31

3 Answers 3

5

Also, the json you shared is an array of CurrencyDTO. Assuming your Json to be,

  {
      "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
         }
      ]
   }

Change your CurrencyDTO as,

@Data
@NoArgsConstructor
public class CurrencyDTO {

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

    private List<Rates> rates;
}

and your Rates class to,

@Data
@NoArgsConstructor
public class Rates {

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

It is able to deserialize for me. What you are doing wrong is that Dto instance variables should be according to name in Json or you should use @JsonProperty("nameInTheJson").

If you want to make it compatible to your JSON you can just use Array of CurrencyDTO You will be able to deserialise, you can use the object as,

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());
        }
Sign up to request clarification or add additional context in comments.

9 Comments

After those changes, I am getting an error in API calling part. How would you approach to solve it? the code is above in try catch block
The method forEach(Consumer <? super Rates>) in the type Iterable<Rates> is not applicable for the arguments ((<no type> key, <no type> value) -> {}) I am using forEach to store data in database via Currency entity class.
is key value in price is currency and mid in json?
After your suggestion and refactoring the code, there is not Map<> interface as price in Rates class.
I have added the try catch block as well
|
0

Firstly, Your JSON is an array of CurrencyDTO, not just a CurrencyDTO as mentioned in the comment and now if it's affecting other parts of your code and you just want to deserialize it as it is then you can do something as follows:

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

Also, I highly recommend that this is the worst way you should be doing it. Prefer updating your API to return a proper response.

Comments

0

if anyone working with nextjs, call api maybe you miss

JSON.stringify so spring boot cannot parse

call api in nextjs

const resPut = await fetch(`${API_URL}/products/${productId}`, {
        method: "PUT",
        headers: {
          Authorization: `Bearer ${token}`,
          "Content-Type": "application/json",
        },
        body: JSON.stringify(req.body),  //   // forget convert json -> json invalid - cannot parse json array
      });

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.