javaspringresttemplatespring-restjackson2

Invalid mime type in spring rest template?


I am just trying to make a simple REST request like below

String url = "some url";
MultiValueMap<String, String> headers = new LinkedMultiValueMap<>();
headers.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
headers.add(HttpHeaders.AUTHORIZATION, "some authorization");
RestTemplate restTemplate = new RestTemplate();
restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
Body body = new Body();
body.setRemarks("test");
org.springframework.http.HttpEntity request = new org.springframework.http.HttpEntity(body, headers);
try {
    ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.PUT, request, String.class);
    System.out.println("Status Response: "+ response.getStatusCode() +". Body: "+ response.getBody());
} catch (HttpClientErrorException | HttpServerErrorException e) {
    e.printStackTrace();
} catch (Exception e) {
    e.printStackTrace();
}

Problem is every time I do this in Java the result is unpredictable I am usually getting this error consistently.

org.springframework.http.InvalidMediaTypeException: Invalid mime type "text/plain, application/json, application/json, application/*+json, application/*+json, */*; charset=UTF-8": Invalid token character ',' in token "plain, application/json, application/json, application/*+json, application/*+json, */*"
at org.springframework.http.MediaType.parseMediaType(MediaType.java:452)
at org.springframework.http.HttpHeaders.getContentType(HttpHeaders.java:745)
at org.springframework.web.client.DefaultResponseErrorHandler.getCharset(DefaultResponseErrorHandler.java:115)
at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:63)
at org.springframework.web.client.RestTemplate.handleResponse(RestTemplate.java:700)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:653)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:613)
at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:531)

However when I try the same request through postman it works. I am missing something very simple and I do not know what.

I checked the response from Postman and the headers, and they seem to hold good like Content-Type →application/json; charset=UTF-8 and the response is also well formed.

I am also not able to make out which part whether the request or the response is on which Rest Template is having a problem.


Solution

  • Short answer in my case was add these extra headers while before making the request.

    headers.add(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE);
    headers.add(HttpHeaders.ACCEPT_CHARSET, StandardCharsets.UTF_8.name());
    

    Long answer: Thanks to Nikolay Shevchenko's suggestion to use debugger to dig out that when there was an error on the server RestTemplate tried to gather up all headers and body from the response to create sane exception message. While trying to create that message from response it got the mime type

    text/plain, application/json, application/json, application/*+json, application/*+json, */*; charset=UTF-8
    

    Yes that entire length of text instead of application/json; charset=UTF-8 as shown for the same request by Postman. So in my case of an older spring rest template version when it tries to parse over the above provided mime type, it fails, producing this message.

    org.springframework.http.InvalidMediaTypeException: Invalid mime type "text/plain, application/json, application/json, application/*+json, application/*+json, */*; charset=UTF-8": Invalid token character ',' in token "plain, application/json, application/json, application/*+json, application/*+json, */*"
    

    So instead of a getting a server error, a more fine grained mime type exception bubbles up from deeper stack, making no sense for what you are searching for.

    As per this post by M. Deinum RestTemplate was some how ending up using StringHttpMessageConverter although I have specified Jackson to Http Message converter as shown below.

    restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
    

    As mentioned in aforementioned post having StringHttpMessageConverter causes writeAcceptCharset to be true which brings along the long format of mime type with almost every possible value. In the mentioned post the solutions were either to make writeAcceptCharset as false or not to write plain string but use object and then marshal it as a string.

    For my use case I was expecting response type to be application/json with charset of UTF-8 so setting up those accept headers in configuration sorted out my problem.