Spring Boot Exception Handling — @ControllerAdvice
Error and Exception handling is essential for a web application and proper responses with reasonable details are required for better debugging and user experience. Spring Boot provides a /error
mapping that handles all errors in a sensible way, and it is registered as a “global” error page in the servlet container. If you are implementing a rest API or a web application with a UI template you will get a proper JSON or HTML view rendered. You will have the option to change this template using different methods.
There are different techniques to handle exceptions at the controller level as well as application level. Using these methods you are able to prepare the proper response with the proper status.
@ControllerAdvice
and@ExceptionHandler
- Using HandlerExceptionResolver (Read In Medium)
- Using ResponseStatusException (Read In Medium)
In this article, we will focus on @ControllerAdvice
and @ExceptionHandler
and make some examples with these annotations to handle exceptions for rest applications and also a web application with an HTML view.
Getting Started
ExceptionHandler
@ExceptionHandler
was there since Spring 3.0 it gives the option to have exception handling at the controller level. This may give you some flexibility that you needed but at the same time, it might consider a drawback since it is only active for a particular Controller.
Rest API Application — In this example, you have a rest application with a student/{id}
URL that has the method with the potential of throwing a InvalidIdException
.
@RestController
@RequestMapping("/api/v1/")
public class StudentRestController {
@Autowired
StudentService studentService;
@GetMapping("student/{id}")
public ResponseEntity<Student> getUser(
@PathVariable(name = "id", required = false) Long id )
throws InvalidIdException, ServiceDownTimeException {
Student student = studentService.findStudentById(id);
return ResponseEntity
.status(HttpStatus.OK)
.body(student);
}
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler({ InvalidIdException.class })
public InvalidIdException handleException(
InvalidIdException exception ) {
return exception;
}
}
if the API call happens with a null or invalid value for Id the handleException method in this controller will be triggered and the user will receive a bad request 400 HTTP status with the exception in the message body as JSON.
{
"cause": null,
"stackTrace": [...],
"localizedMessage": "Invalid ID",
"message": "Invalid ID",
"suppressed": []
}
Web UI Application — In this example, you have a web application with a dashboard
URL that has a method that throws a InvalidIdException
.
@Controller
@RequestMapping("/panel")
public class StudentController { @Autowired
StudentService studentService;@GetMapping("/dashboard")
public String dashboard(
@RequestParam(name = "id", required = false) Long id ,
Model model )
throws InvalidIdException, ServiceDownTimeException {
Student student = studentService.findStudentById(id);
model.addAttribute("student",student);
return "dashboard";
}@ExceptionHandler({ InvalidIdException.class })
public String handleException(
InvalidIdException exception ,
Model model ) {
model.addAttribute("message", exception.getMessage() );
return "error-custom";
}}
Using @ExceptionHandler
and specifying the relevant Exception(s) you can manage to view the custom error page view with the expected template. in our example in case of an Exception for an invalid Id user will see the error-custom.html
view and the error message that is provided.
ControllerAdvice
@ControllerAdvice
was available from Spring 3.2 and made exception handling in the application much easier. Having the @ControllerAdvice
on your class and handling the exception by different methods will function like an Interceptor and in case any of the controllers throw the Exception it will be handled by the related method.
@ControllerAdvice
public class ExceptionControllerAdvice {
@ResponseBody
@ResponseStatus(HttpStatus.SERVICE_UNAVAILABLE)
@ExceptionHandler(value= { ServiceDownTimeException.class })
protected ServiceDownTimeException handleConflict(ServiceDownTimeException exception, HttpServletResponse response) {
return exception;
}
}
The @ExceptionHandler
is used to specify the type of the Exception and the method with that annotation will function as the handler. @ResponseBody
will help to have the object in the response rather than the name of the template file.
If you Test the code you will notice that In case of ServiceDownTimeException
you will get the following response:
{
"cause": null,
"stackTrace": [],
"localizedMessage": "1-2 AM is service downtime!",
"message": "1-2 AM is service downtime!",
"suppressed": []
}
The Example code is available on GitHub. You can learn more about the other methods of handling exceptions in the following articles:
Hope this article helped you and please support me with your applauding 👏 for the story. if you don’t know how it is just like this:
Or buy me a coffee here!