Spring Boot Exception Handling
Exception Handling
By default, Spring Boot returns JSON with exception details and an HTTP status code to REST clients. Browsers receive the Whitelabel Error Page.
Specify a Status Code for an Exception
package sample.springboot.web;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;
@ResponseStatus(HttpStatus.BAD_REQUEST)
public class MyException extends RuntimeException {
private static final long serialVersionUID = 1L;
public MyException(String msg) { super(msg); }
}
package sample.springboot.web;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/api")
public class WebApiController {
@RequestMapping(method=RequestMethod.GET)
public void method1() { throw new MyException("test exception"); }
}
$ curl http://localhost:8080/api
{"timestamp":1430489386562,"status":400,"error":"Bad Request","exception":"sample.springboot.web.MyException","message":"test exception","path":"/api"}
Annotating an exception class with @ResponseStatus defines the status returned when it is thrown. Browsers still receive the default error page.
Handle All Exceptions
package sample.springboot.web;
import javax.servlet.http.*;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.*;
@Component
public class MyExceptionResolver implements HandlerExceptionResolver {
@Override
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
System.out.println(ex.getClass() + " : " + ex.getMessage());
ModelAndView mv = new ModelAndView();
mv.setViewName("my-error");
return mv;
}
}
<h1>My Error Page</h1>
Add the following method to WebApiController:
@RequestMapping(value="/null", method=RequestMethod.GET)
public void method2() {
throw new NullPointerException("test exception");
}
$ curl http://localhost:8080/api
{"timestamp":1430490625809,"status":400,"error":"Bad Request","exception":"sample.springboot.web.MyException","message":"test exception","path":"/api"}
$ curl http://localhost:8080/api/null
<h1>My Error Page</h1>
Implement HandlerExceptionResolver and register it with @Component. Its resolveException() method is called for controller exceptions and can return a ModelAndView. Exceptions annotated with @ResponseStatus are handled before this resolver.
Return JSON for Web API Requests
Update the resolver so REST controllers use the default handling:
@Component
public class MyExceptionResolver implements HandlerExceptionResolver {
@Override
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
if (isRestController(handler)) return null;
ModelAndView mv = new ModelAndView();
mv.setViewName("my-error");
return mv;
}
private boolean isRestController(Object handler) {
if (handler instanceof HandlerMethod) {
HandlerMethod method = (HandlerMethod)handler;
return method.getMethod().getDeclaringClass().isAnnotationPresent(RestController.class);
}
return false;
}
}
$ curl http://localhost:8080/api/null
{"timestamp":1430490749586,"status":500,"error":"Internal Server Error","exception":"java.lang.NullPointerException","message":"test exception","path":"/api/null"}
Returning null from resolveException() delegates to default handling. Use a regular @Controller and return an error page when browser navigation should render a view.
Define Exception Handling per Controller
Add an @ExceptionHandler method to WebApiController:
@ExceptionHandler(NullPointerException.class)
public String handling(NullPointerException e) {
return "{\"message\":\"" + e.getMessage() + "\"}";
}
$ curl http://localhost:8080/api/null
{"message":"test exception"}
@ExceptionHandler handles the specified exception type only within that controller.