Search code examples
javajsonspringspring-mvcresttemplate

RestTemplate mapping to Map instead of fields


I've wrote simple currency converter which reads JSON from web service and prepare table on website with selected ratios.

Until now, my Rates class had field for each ratio, but I decided to change it to Map. I rewrote entire class using Map but RestTemplate is unable to map JSON data to my HashMap. Entire field is considered as null. How can I reconfigure RestTemplate or ObjectMapper to enable mapping JSON to Map?

Example JSON string that I am trying to map

Repository class I am using to read JSON and to map it on object: package com.github.gromo13.currencyConverter.repository;

import com.github.gromo13.currencyConverter.model.Currency;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.web.client.RestTemplate;

@Repository
public class FixerIoCurrencyRepository implements CurrencyRepository {
    @Autowired
    private RestTemplate restTemplate;

    public void setRestTemplate(RestTemplate restTemplate) {
        this.restTemplate = restTemplate;
    }

    @Override
    public Currency getCurrency(String currencyCode) {
        Currency currency = restTemplate.getForObject("http://api.fixer.io/latest?base={currencyCode}", Currency.class, currencyCode);

        return currency;
    }
}

Currency class I am mapping using JSON data: package com.github.gromo13.currencyConverter.model;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;

@JsonIgnoreProperties(ignoreUnknown = true)
public class Currency {
    private String base;
    private String date;
    private Rates rates;

    public String getBase() {
        return this.base;
    }

    public void setBase(String base) {
        this.base = base;
    }

    public String getDate() {
        return this.date;
    }

    public void setDate(String date) {
        this.date = date;
    }

    public Rates getRates() {
        return this.rates;
    }

    public void setRates(Rates rates) {
        this.rates = rates;
    }
}

Rates class (field in Currency class) with Map that i am unable to map: package com.github.gromo13.currencyConverter.model; import com.fasterxml.jackson.annotation.JsonIgnoreProperties;

import java.util.HashMap;
import java.util.Map;

@JsonIgnoreProperties(ignoreUnknown = true)
public class Rates {
    private Map<String, Double> rates = new HashMap<>();

    public void clear() {
        rates.clear();
    }

    public void setRate(String currencyCode, double rate) {
        rates.put(currencyCode.toUpperCase(), rate);
    }

    public double getRate(String currencyCode) {
        return rates.get(currencyCode.toUpperCase());
    }
}

My actual RestTemplate configuration: package com.github.gromo13.currencyConverter.config;

import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.client.RestTemplate;

@Configuration
public class Config {
    @Bean
    public RestTemplate restTemplate() {
        RestTemplate restTemplate = new RestTemplate();
        restTemplate.getMessageConverters().add(0, mappingJackson2HttpMessageConverter());

        return restTemplate;
    }

    @Bean
    public ObjectMapper objectMapper() {
        ObjectMapper mapper = new ObjectMapper();
        mapper.configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES, true);

        return mapper;
    }

    @Bean
    public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() {
        MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
        converter.setObjectMapper(objectMapper());

        return converter;
    }
}

Solution

  • It is not going to work the way you have it now. You don't need the Rates class, you can get rid of it entirely and use:

    private Map<String, Double> rates
    

    in the currency class.