Reputation: 1399
I have custom errors handling in my REST webservice. I have methods returning XML / JSON as response. Everything worked fine on SpringBoot version 2.0.9. But after migration to latest (2.2.4) my error handling tests fail:
Content type expected:<application/xml> but was:<application/json>
Expected :application/xml
Actual :application/json
After research I found that it's related with upgrading Spring to Version 5.1. Docs:
Content Negotiation for Error Responses The produces condition of an @RequestMapping no longer impacts the content type of error responses.
How can I reproduce behavior from earlier versions of Spring in the latest? I just want to return the content type for errors as specified in produces condition.
Rest methods:
@PostMapping(path = "/{scriptName}", produces = { MediaType.APPLICATION_XML_VALUE })
public ResponseEntity<Object> xmlMethod(@RequestParam("payload") String payload, @PathVariable("scriptName") String scriptName) {
Object result = service.call(payload, scriptName);
return ResponseEntity.ok(new JsonBuilder(result).getContent());
}
@PostMapping(path = "/{scriptName}", produces = { MediaType.APPLICATION_JSON_VALUE })
public ResponseEntity<Object> jsonMethod(@RequestParam("payload") String payload, @PathVariable("scriptName") String scriptName) {
Object result = service.call(payload, scriptName);
return ResponseEntity.ok(new JsonBuilder(result).getContent());
}
CustomRestExceptionHandler:
@ControllerAdvice
public class CustomRestExceptionHandler extends ResponseEntityExceptionHandler {
@ExceptionHandler(ResourceNotFoundException.class)
public ResponseEntity<Object> handleResourceNotFoundException(ResourceNotFoundException ex, WebRequest request) {
HTTPErrorDTO httpError = new HTTPErrorDTO(HttpStatus.NOT_FOUND, ex.getLocalizedMessage());
return new ResponseEntity<>(httpError, new HttpHeaders(), httpError.getStatus());
}
....
// handlers for other exceptions
}
Error DTO:
@XmlRootElement(name = "Exception")
@XmlAccessorType(XmlAccessType.FIELD)
public class HTTPErrorDTO {
private HttpStatus status;
private String message;
private List<String> errors;
}
Related topic: Spring mvc - Configuring Error handling for XML and JSON Response
---EDIT
I tried to add custom content negotiation configuration. But one of clients of my REST API send me content-type = "application/x-www-form-urlencoded" and expect application/xml and don't send any accept headers.
So I can only decide what format the content type should be at the method/controller level.
Can I somehow inform exception handler from controller, which one content type should be set?
Upvotes: 3
Views: 3708
Reputation: 638
You can pass a HandlerMethod
object to an exception handler method (i.e. handleResourceNotFoundException
in your question).
@ExceptionHandler(ResourceNotFoundException.class)
public ResponseEntity<Object> handleResourceNotFoundException(
ResourceNotFoundException ex,
WebRequest request,
HandlerMethod handlerMethod) {
........
}
The HandlerMethod
object represents the controller method that raised the exception. So you can get values of produces
from an @RequestMapping
annotation on the object.
RequestMapping requestMapping = handlerMethod.getMethodAnnotation(RequestMapping.class);
String[] produces = requestMapping.produces();
....
In your source code of the question, produces
is an array that has an element (i.e. MediaType.APPLICATION_XML_VALUE
or MediaType.APPLICATION_JSON_VALUE
).
Upvotes: 2
Reputation: 130957
In your CustomRestExceptionHandler
, you can set a media type for the ResponseEntity
.
return ResponseEntity.status(httpError.getStatus().value())
.contentType(MediaType.APPLICATION_XML)
.body(httpError);
Upvotes: 1