14

I struggled with an extrange spring behavior using RestTemplate (org.springframework.web.client.RestTemplate) without success.

I use in my hole application below code and always receive an XML response, which I parse and evaluate its result.

String apiResponse = getRestTemplate().postForObject(url, body, String.class);

But can't figure out why a server response is in JSON format after executing:

String apiResponse = getRestTemplate().getForObject(url, String.class);

I've debugged at low level RestTemplate and the content type is XML, but have no idea why the result is in JSON.

When I access from a browser the response is also in XML, but in apiResponse I got JSON.

I tried many options after reading Spring documentation http://docs.spring.io/spring/docs/3.0.x/api/org/springframework/web/client/RestTemplate.html

Also tried to modify explicitly the headers but still can't figure it out.

I debugged RestTemplate class and noticed that this method is always setting application/json:

public void doWithRequest(ClientHttpRequest request) throws IOException {
            if (responseType != null) {
                List<MediaType> allSupportedMediaTypes = new ArrayList<MediaType>();
                for (HttpMessageConverter<?> messageConverter : getMessageConverters()) {
                    if (messageConverter.canRead(responseType, null)) {
                        List<MediaType> supportedMediaTypes = messageConverter.getSupportedMediaTypes();
                        for (MediaType supportedMediaType : supportedMediaTypes) {
                            if (supportedMediaType.getCharSet() != null) {
                                supportedMediaType =
                                        new MediaType(supportedMediaType.getType(), supportedMediaType.getSubtype());
                            }
                            allSupportedMediaTypes.add(supportedMediaType);
                        }
                    }
                }
                if (!allSupportedMediaTypes.isEmpty()) {
                    MediaType.sortBySpecificity(allSupportedMediaTypes);
                    if (logger.isDebugEnabled()) {
                        logger.debug("Setting request Accept header to " + allSupportedMediaTypes);
                    }
                    request.getHeaders().setAccept(allSupportedMediaTypes);
                }
            }
        }

Could you give an idea?

Federico Piazza
  • 30,085
  • 15
  • 87
  • 123
  • 1
    If the browser you used is Firefox, the problem is the accept header, `RestTemplate` is low level and just perform a basic GET –  Feb 06 '14 at 20:44
  • RC is right, need to look at the request headers and content response types to figure this out. Please provide more context for your problem. – Pedantic Feb 06 '14 at 20:46
  • @RC, I've just updated the post with new information. Seems that the allSupportedMediaTypes is always with application/json. If modify it through the debugger to application/xml it works. Why does it happen? By the way, how can I do to use application/xml by default? – Federico Piazza Feb 06 '14 at 20:53
  • @Pedantic, the isse happens because "allSupportedTypes" contains application/json and it is added to setAccept. I need to figure out why json is set and how to change it. Thanks a lot – Federico Piazza Feb 06 '14 at 21:04
  • @Fede, just inspect what your browser (the xml one) is sending as accept header and content type and add those headers to your `RestTemplate` (with an interceptor). –  Feb 06 '14 at 21:11
  • @RC. I've followed this link to add the converter to messageConverter but when I add Jaxb it didn't convert the response. RC. Could you give me an example of the interceptor? – Federico Piazza Feb 06 '14 at 21:35
  • @RC. as you said, seems that String.class gets converted to the AcceptHeaderRequestCallback and the only response extractor is JSON. Do you know what T.class I can use to generate XML response? – Federico Piazza Feb 06 '14 at 21:50
  • 1
    see [this answer](http://stackoverflow.com/a/19239013/180100) –  Feb 06 '14 at 22:04
  • @RC. thanks, that answer solved my issue. Although, can you explain me why Spring automatically sets up JSON? In all my application I used postForObject and it always used XML. By the way, thanks a lot. – Federico Piazza Feb 06 '14 at 22:17
  • Spring honours its default configuration (convention) and your configuration, you'll have to check the doc and your config to know why JSON is the default. –  Feb 06 '14 at 22:40

1 Answers1

25

I could solve my issue with RC.'s help. I'll post the answer to help other people.

The problem was that Accept header is automatically set to APPLICATION/JSON so I had to change the way to invoke the service in order to provide the Accept header I want.

I changed this:

String response = getRestTemplate().getForObject(url, String.class);

To this in order to make the application work:

// Set XML content type explicitly to force response in XML (If not spring gets response in JSON)
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Arrays.asList(MediaType.APPLICATION_XML));
HttpEntity<String> entity = new HttpEntity<String>("parameters", headers);

ResponseEntity<String> response = getRestTemplate().exchange(url, HttpMethod.GET, entity, String.class);
String responseBody = response.getBody();
Federico Piazza
  • 30,085
  • 15
  • 87
  • 123
  • I could also solve my issue with the above mentioned piece of code. Thanks Fede! – Rushi Shah Jul 16 '14 at 15:11
  • 4
    For me this does not work because my content type is application/json;UTF-8. Could not extract response: no suitable HttpMessageConverter found for response type ...classname... and content type [application/json;charset=UTF-8] – Mejmo Jul 24 '15 at 13:13
  • Fist time a thought was a converter or "generic" problem, but wasn't. Your solution works like charm! At least for me, thx! – davidwillianx Sep 05 '19 at 13:03
  • Setting the expectation solved my issue: headers.setAccept(Arrays.asList(MediaType.APPLICATION_XML)); Thanks buddy :) – Pratik Ambani Jul 21 '20 at 04:55