I have an error message class:
@XmlRootElement
public class ErrorMessage {
private String message;
public ErrorMessage() {
}
public ErrorMessage(String message) {
this.message = message;
}
public String getError() {
return message;
}
public void setError(String message) {
this.message = message;
}
}
This class has been assigned as a return value to an @ExceptionHandler in my Spring MVC REST controller:
@ExceptionHandler
@ResponseStatus(HttpStatus.NOT_FOUND)
@ResponseBody
ErrorMessage handleException(RuntimeException e) {
return new ErrorMessage("something went wrong");
}
Whenever the client triggers a RuntimeException
after issuing a request with application/json
as a Accept
header, it receives a response with the correct status code and a matching JSON body:
{"error":"something went wrong"}
Alternatively, an XML body is received if the Accept
header is application/xml
:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<errorMessage><error>something went wrong</error></errorMessage>
Now, I would like to generify this solution by implementing a HandlerExceptionResolver instead so I don't have to copy / paste the @ExceptionHandler
to every controller (or create a common "parent controller" that the other controllers can extend).
However, the AbstractHandlerExceptionResolver.doResolveException() method returns a ModelAndView
and not my propriety ErrorMessage
, so I tried the following:
public class RuntimeExceptionHandlerExceptionResolver extends AbstractHandlerExceptionResolver {
@Override
protected ModelAndView doResolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
if (ex instanceof RuntimeException) {
response.setStatus(HttpServletResponse.SC_NOT_FOUND);
ModelAndView mav = new ModelAndView();
mav.addObject("error", "something went wrong");
return mav;
}
return null;
}
}
When debugging, I can see that the mav.addObject()
method is called. The response on the client side has the expected status code, but the content type is text/html
with html in the body, rather than the JSON or XLM content that was specified by the Accept
header in the original request.
(Side note, the actual exception, response code and text message in the example above is not important, they just serve as simple example.)
Spring version: 3.1.1.RELEASE
Spring MVC Framework provides following ways to help us achieving robust exception handling. Controller Based - We can define exception handler methods in our controller classes. All we need is to annotate these methods with @ExceptionHandler annotation. This annotation takes Exception class as argument.
Spring MVC provides exception handling for your web application to make sure you are sending your own exception page instead of the server-generated exception to the user. The @ExceptionHandler annotation is used to detect certain runtime exceptions and send responses according to the exception.
The most basic way of returning an error message from a REST API is to use the @ResponseStatus annotation. We can add the error message in the annotation's reason field. Although we can only return a generic error message, we can specify exception-specific error messages.
To get @ExceptionHandler
s to use content negotiation, the AnnotationMethodHandlerExceptionResolver
has a setMessageConverters()
method which must be provided with the message converters, e.g.:
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerExceptionResolver">
<property name="messageConverters">
<list>
<ref bean="xmlConverter"/>
<ref bean="jsonConverter"/>
</list>
</property>
</bean>
But since you're using a custom method, you'll probably have to implement this functionality yourself. The simplest way is probably to Ctrl-C Ctrl-V
from the AnnotationMethodHandlerExceptionResolver
source, specifically the handleResponseBody()
method.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With