Issue
I am making a call to one of the Jasper server API endpoints and I have to set the header "Accept" to "application/json" for the service to return a JSON response. I have validated the API from Postman -
When I try to simulate the same behavior from my Spring Boot rest client, I try to set the accept header to 'application/json' but Spring seems to ignore the same and adds the accept header as shown below -
I have validated the same by enabling DEBUG for rest template using the following parameter - logging.level.org.springframework.web.client.RestTemplate=DEBUG
Below is the code snippet for my rest client -
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
headers.setContentType(MediaType.APPLICATION_JSON);
headers.setBasicAuth(serviceUsername, servicePassword, StandardCharsets.UTF_8);
ResponseEntity<String> response = null;
String url = serviceEndpoint + "?reportUnitURI="
+ URLEncoder.encode(reportPath, StandardCharsets.UTF_8.toString()).replaceAll("\\+", "%20")
+ "&label=" + URLEncoder.encode(label, StandardCharsets.UTF_8.toString()).replaceAll("\\+", "%20");
LOGGER.info("URL : " + url);
HttpEntity<String> requestEntity = new HttpEntity<String>("",
headers);
response = restTemplate.exchange(url, HttpMethod.GET, requestEntity, String.class);
- Can someone please help explain the behavior here?
- Why does my header values for 'accept' gets ignored?
- What could be done to pass the 'accept' header properly?
Solution
Even though the code sets the accept header, the HttpMessageConverter used my scenario (StringHttpMessageConverter) does not allow changes on the accept headers and maintains the default values.
To get past that I have modified the StringHttpMessageConverter behavior at runtime to allow setting the preferred accept header.
@Bean
public RestTemplate getRestTemplate() {
final RestTemplate restTemplate = new RestTemplate();
final List<HttpMessageConverter<?>> converters = new ArrayList<>();
for (HttpMessageConverter converter : restTemplate.getMessageConverters()) {
if (converter instanceof StringHttpMessageConverter) {
((StringHttpMessageConverter) converter).setWriteAcceptCharset(true);
((StringHttpMessageConverter) converter).setSupportedMediaTypes(Collections.singletonList(MediaType.APPLICATION_JSON));
converters.add(converter);
}
}
restTemplate.setMessageConverters(converters);
return restTemplate;
}
Now, the framework allows my REST client to modify the header, code snippet below -
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
headers.setBasicAuth(serviceUsername, new String(new DecryptionService().decrypt(servicePassword)), StandardCharsets.UTF_8);
ResponseEntity<String> response = null;
try {
String url = serviceEndpoint + "?reportUnitURI=" + reportPath + "&label=" + processLabel(label, false);
HttpEntity<String> requestEntity = new HttpEntity<String>("",
headers);
response = restTemplate.exchange(url, HttpMethod.GET, requestEntity, String.class);
//more stuff
Answered By - Siddhartha
Answer Checked By - Marilyn (JavaFixing Volunteer)