I have a Rest web service based on Spring MVC. I use a @RestControllerAdvice
to handle exceptions thrown from my @Controller
s.
Controller
An example of call is as below
@GetMapping(value = "/{id}/{name:.+}", produces = { MediaType.APPLICATION_OCTET_STREAM_VALUE,
MediaType.APPLICATION_XML_VALUE, MediaType.APPLICATION_JSON_VALUE })
ResponseEntity<byte[]> getSomething(
@PathVariable("id") String id, @PathVariable("name") String name) throws customException;
A basic method that can produce 3 media types : APPLICATION_OCTET_STREAM_VALUE
, APPLICATION_XML_VALUE
and APPLICATION_JSON_VALUE
and throws a customException
Exception handler
The definition of my @RestControllerAdvice
is as the following :
@ExceptionHandler({ CustomException.class })
public ResponseEntity<Object> handleException(CustomException e) {
ErrorDto err = errorMapper.map(e);
Enumeration<String> en = httpServletRequest.getHeaders(HttpHeaders.ACCEPT);
while (en.hasMoreElements()) {
String list = en.nextElement();
StringTokenizer st = new StringTokenizer(list, ",");
while (st.hasMoreTokens()) {
String acc = st.nextToken();
MediaType contentTypeHeader = MediaType.valueOf(acc);
if (MediaType.APPLICATION_XML.includes(contentTypeHeader)) {
JAXBElement<ErrorDto> ret = new ObjectFactory().createError(err);
return ResponseEntity.status(HttpStatus.PRECONDITION_FAILED)
.contentType(MediaType.APPLICATION_XML).body(ret);
} else if (MediaType.APPLICATION_JSON.includes(contentTypeHeader)) {
return ResponseEntity.status(HttpStatus.PRECONDITION_FAILED)
.contentType(MediaType.APPLICATION_JSON).body(err);
}
}
}
return ResponseEntity.status(HttpStatus.NOT_ACCEPTABLE).body(null);
}
According to the request accept header, the @ExceptionHandler
returns a null body and a NOT_ACCEPTABLE
http response status if no accept is set, or a object of type ErrorDto
if accept is of type APPLICATION_JSON
or a JaxbElement
of ErrorDto
is accept is of type APPLICATION_XML
Please note that I specify the content type of the response when it contains a body.
Problem
My problem is when a client make a call with multiple accept headers, Spring tries to pick up an HttpMessageConverter
according to the accept header and not to the response content type. Below an example :
When the client call a method that throws an exception (and then returns an errorDto) with multiple Accept headers as below :
HttpHeaders headers = new HttpHeaders();
headers.add(HttpHeaders.ACCEPT, MediaType.APPLICATION_OCTET_STREAM_VALUE);
headers.add(HttpHeaders.ACCEPT, MediaType.APPLICATION_XML_VALUE);
HttpEntity<?> entity = new HttpEntity<>(body, headers);
restTemplate.exchange(uriComponents.encode().toUri(), httpMethod, entity, Class);
Spring does not return a response with the error in the XML format as expected. It looks for a Octet-Stream <-> JaxbElement
converter that does not exist and does not try to find the converter according to the response content type.
How can I force Spring to use a converter according to the response content type ?
I'm using :
- Spring Boot 1.4.0.RELEASE