Search code examples
javaspring-bootjacksonapache-commonsmultimap

Error when using RestTemplate - problem with deserialization of object with Apache Commons Multimap


I am trying to retreive using RestTemplate object from service.

HttpHeaders headers = new HttpHeaders();
    headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
    headers.setContentType(MediaType.APPLICATION_JSON);

    HttpEntity<BusinessPartnerRequest> entity = new HttpEntity<>(request, headers);

    ResponseEntity<Analysis> result = restTemplate.exchange(url, HttpMethod.POST, entity, Analysis.class);

Unfortunately I got Exception each time. This is the exception:

Could not extract response: no suitable HttpMessageConverter found for response type [class com.abb.bttr.validator.Analysis] and content type [application/json;charset=UTF-8]

I know that this is general exception and mapper return it every time there will be any Exception.

So I found real cause: Cannot find a deserializer for non-concrete Map type [map type; class org.apache.commons.collections4.MultiMap, [simple type, class java.lang.String] -> [simple type, class java.lang.Object]]

My Analysis object:

import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.MapSerializer;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
import org.apache.commons.collections4.MultiMap;
import org.apache.commons.collections4.map.MultiValueMap;

    @JacksonXmlRootElement
    public class Analysis {
        private Boolean error = false;
        @JsonSerialize(keyUsing = MapSerializer.class)
        private MultiMap<String, String> errorDetails = new MultiValueMap<>();

        //getter, setters, constructors, equals and hashcode
    }

Do you know a way to deserialize ApacheCommons MultiMap in quick way? I can use guava, but I don't want to add Guava library just for Multimap.


Solution

  • You can instruct which type you want to use for MultiMap by using SimpleModule class. See below code:

    import com.fasterxml.jackson.databind.ObjectMapper;
    import com.fasterxml.jackson.databind.module.SimpleModule;
    import java.io.IOException;
    import org.apache.commons.collections4.MultiMap;
    import org.apache.commons.collections4.map.MultiValueMap;
    
    public class JsonApp {
    
      public static void main(String[] args) throws IOException {
        MultiMap<String, String> multiMap = new MultiValueMap<>();
        multiMap.put("a", "AA");
        multiMap.put("a", "AAA");
        multiMap.put("b", "B");
        multiMap.put("b", "BB");
    
        SimpleModule collections4Module = new SimpleModule();
        collections4Module.addAbstractTypeMapping(MultiMap.class, MultiValueMap.class);
    
        ObjectMapper jsonMapper = new ObjectMapper();
        jsonMapper.registerModule(collections4Module);
    
        String json = jsonMapper.writeValueAsString(multiMap);
        System.out.println(json);
        System.out.println(jsonMapper.readValue(json, MultiMap.class));
      }
    }
    

    Above code prints:

    {"a":["AA","AAA"],"b":["B","BB"]}
    {a=[[AA, AAA]], b=[[B, BB]]}