Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

resttemplate getForObject map responsetype

Update 02/05/2018 (about 4 years later)...I tested this again as people have been upvoting my question/answer and Sotirios Delimanolis is correct that I should not have to write the code in my answer to make this work. I used basically the same RestTemplate/REST service setup as shown in my question with the REST service having a confirmed response content type of application/json and RestTemplate was able to process the response with no issues into a Map.


I'm invoking a rest service that returns JSON like this:

{
   "some.key" : "some value",
   "another.key" : "another value"
}

I would like to think that I can invoke this service with a java.util.Map as the response type but that's not working for me. I get this exception:

org.springframework.web.client.RestClientException: Could not extract response: no suitable HttpMessageConverter found for response type [interface java.util.Map]

Should I just specify String as the response type and convert the JSON to a Map?

Edit I

Here's my restTemplate call:

private Map<String, String> getBuildInfo(String buildUrl) {
    return restTemplate.getForObject(buildUrl, Map.class);
}

Here's how I'm setting up the restTemplate:

@PostConstruct
public void initialize() {
    List<ClientHttpRequestInterceptor> interceptors = new ArrayList<>();
    interceptors.add(new ClientHttpRequestInterceptor() {
        @Override
        public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
            HttpRequestWrapper requestWrapper = new HttpRequestWrapper(request);
            requestWrapper.getHeaders().setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
            return execution.execute(requestWrapper, body);
        }
    });
    restTemplate.setInterceptors(interceptors);
}

Edit II

Full error message:

org.springframework.web.client.RestClientException: Could not extract response: no suitable HttpMessageConverter found for response type [interface java.util.Map] and content type [application/octet-stream]
    at org.springframework.web.client.HttpMessageConverterExtractor.extractData(HttpMessageConverterExtractor.java:108) ~[spring-web-4.0.3.RELEASE.jar:4.0.3.RELEASE]
    at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:549) ~[spring-web-4.0.3.RELEASE.jar:4.0.3.RELEASE]
    at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:502) ~[spring-web-4.0.3.RELEASE.jar:4.0.3.RELEASE]
    at org.springframework.web.client.RestTemplate.getForObject(RestTemplate.java:239) ~[spring-web-4.0.3.RELEASE.jar:4.0.3.RELEASE]
    at idexx.ordering.services.AwsServersServiceImpl.getBuildInfo(AwsServersServiceImpl.java:96) ~[classes/:na]
like image 933
Zack Macomber Avatar asked Jun 13 '14 15:06

Zack Macomber


People also ask

What is difference between getForObject and getForEntity in RestTemplate?

For example, the method getForObject() will perform a GET and return an object. getForEntity() : executes a GET request and returns an object of ResponseEntity class that contains both the status code and the resource as an object. getForObject() : similar to getForEntity() , but returns the resource directly.

How do you use RestTemplate getForObject?

The getForObject method fetches the data for the given response type from the given URI or URL template using HTTP GET method. To fetch data for the given key properties from URL template we can pass Object Varargs and Map to getForObject method. The getForObject returns directly the object of given response type.

How do you parse a RestTemplate response?

RestTemplate restTemplate = new RestTemplate(); ResponseEntity<User[]> response = restTemplate. exchange(URL_GET,HttpMethod. GET,request, User[]. class);


4 Answers

RestTemplate has a method named exchange that takes an instance of ParameterizedTypeReference as parameter.

To make a GET request that returns a java.util.Map, just create an instance of an anonym class that inherits from ParameterizedTypeReference.

ParameterizedTypeReference<HashMap<String, String>> responseType = 
               new ParameterizedTypeReference<HashMap<String, String>>() {};

You can then invoke the exchange method:

RequestEntity<Void> request = RequestEntity.get("http://example.com/foo")
                 .accept(MediaType.APPLICATION_JSON).build();
Map<String, String> jsonDictionary = restTemplate.exchange(request, responseType).getBody();
like image 129
JeremyW Avatar answered Oct 06 '22 07:10

JeremyW


As I had previously noted, your error message is showing us that you are receiving application/octet-stream as a Content-Type.

org.springframework.web.client.RestClientException: Could not extract response: no suitable HttpMessageConverter found for response type [interface java.util.Map] and content type [application/octet-stream]

As such, Jackson's MappingJackson2HttpMessageConverter cannot parse the content (it's expecting application/json).


Original answer:

Assuming your HTTP response's Content-Type is application/json and you have have Jackson 1 or 2 on the classpath, a RestTemplate can deserialize JSON like you have into a java.util.Map just fine.

With the error you are getting, which you haven't shown in full, either you've registered custom HttpMessageConverter objects which overwrite the defaults ones, or you don't have Jackson on your classpath and the MappingJackson2HttpMessageConverter isn't registered (which would do the deserialization) or you aren't receiving application/json.

like image 34
Sotirios Delimanolis Avatar answered Oct 06 '22 05:10

Sotirios Delimanolis


I think you can achieve what you're aiming for simply using the RestTemplate and specifying a JsonNode as the response type.

    ResponseEntity<JsonNode> response = 
         restTemplate.exchange(url, HttpMethod.GET, entity, JsonNode.class);

    JsonNode map = response.getBody();

    String someValue = map.get("someValue").asText();
like image 22
riversidetraveler Avatar answered Oct 06 '22 05:10

riversidetraveler


Update 02/05/2018 (about 4 years later)...I tested this again as people have been upvoting my question/answer and Sotirios Delimanolis is correct that I should not have to write the code in my answer to make this work. I used basically the same RestTemplate/REST service setup as shown in my question with the REST service having a confirmed response content type of application/json and RestTemplate was able to process the response with no issues into a Map.


I ended up getting the contents as a String and then converting them to a Map like this:

String json = restTemplate.getForObject(buildUrl, String.class);
Map<String,String> map = new HashMap<String,String>();
ObjectMapper mapper = new ObjectMapper();

try {
    //convert JSON string to Map
   map = mapper.readValue(json, new TypeReference<HashMap<String,String>>(){});
} catch (Exception e) {
     logger.info("Exception converting {} to map", json, e);
}

return map;
like image 39
Zack Macomber Avatar answered Oct 06 '22 05:10

Zack Macomber