· programming  · 3 min read

Controller Advice - Exception Handler in Spring Boot

In this post, I will show how we can use the annotation @ControllerAdvice - Controller Advice - an exception handler in the Spring Boot application. If you want to read how to handle uncaught exceptions in Spring Boot, you can check my old post.

What is @ControllerAdvice ?

Spring 3.2 introduced an annotation @ControllerAdvice. The annotation allows the handling of exceptions across the application. Before this, Spring offered another annotation @ExceptionHandler for exception handling. But, you have to add this annotation in each controller class of your application. It doesn’t help on the application level.

@ControllerAdvice is an annotation-driven interceptor. It intercepts most of those classes that include @RequestMapping.

Comparison with @ExceptionHandler

In most controller classes, you can add @ExceptionHandler annotation to handle exceptions for that class. Nevertheless, in such classes, one can add an extra method to handle exceptions thrown by @RequestMapping methods in the same controller. These exception handling methods can redirect the user to the error page OR build a custom error response.

This will look like below:

@RestController
@RequestMapping("/companies")
public class CompanyController
{

  @GetMapping
  public List<Company> getAllCompanies(HttpServletRequest req) throws Exception {

  }
  @ExceptionHandler(Exception.class)
  public ModelAndView handleError(HttpServletRequest req, Exception ex) {
    logger.error("Request: " + req.getRequestURL() + " raised " + ex);

    ModelAndView mav = new ModelAndView();
    mav.addObject("exception", ex);
    mav.addObject("url", req.getRequestURL());
    mav.setViewName("error");
    return mav;
  }

}

Additionally, you can see the method getAllCompanies throw an Exception. The method handleError will handle the exception thrown by getAllCompanies.

Furthermore, if I have another controller like UserController, I will end up writing like below if it has to handle exceptions.

@RestController
@RequestMapping("/users")
public class UserController
{

  @GetMapping
  public List<User> getAllUsers(HttpServletRequest req) throws Exception {

  }
  @ExceptionHandler(Exception.class)
  public ModelAndView handleError(HttpServletRequest req, Exception ex) {
    logger.error("Request: " + req.getRequestURL() + " raised " + ex);

    ModelAndView mav = new ModelAndView();
    mav.addObject("exception", ex);
    mav.addObject("url", req.getRequestURL());
    mav.setViewName("error");
    return mav;
  }

}

Henceforth, this makes a lot of duplicate code. This is where Controller Advice comes into the picture with an advantage.

Example of Controller Advice

A Controller Advice allows you to use the same exception handling technique across applications, without repeating any code.

Consequently, a class annotated with @ControllerAdvice implements three types of methods:

  • Exception handling method annotated with @ExceptionHandler
  • Model enhancement methods annotated with @ModelAttribute
  • Binder initialization methods annotated with @InitBinder

@ControllerAdvice
public class GlobalExceptionHandler
{

    @ExceptionHandler(CompanyNotFoundException.class)
    public ModelAndView handleError(HttpServletRequest req, CompanyNotFoundException ex)
    {
       logger.error("Request: " + req.getRequestURL() + " raised " + ex);

       ModelAndView mav = new ModelAndView();
       mav.addObject("exception", ex);
       mav.addObject("url", req.getRequestURL());
       mav.setViewName("error");
       return mav;
     }

    @ExceptionHandler(UserNotFoundException.class)
    public ResponseEntity handleUserExceptionError(HttpServletRequest req, HttpServletResponse res, UserNotFoundException ex)
    {
       List errors = Collections.singletonList(ex.getMessage());
       // Get headers
       if(HttpStatus.INTERNAL_SERVER_ERROR.equals(res.getStatus()))
       {
         // do something
       }

       return new ResponseEntity<>(new ApiError(errors), headers, status);
    }

}

This will allow now to intercept any exception thrown from controllers. This makes implementing exception handling easier.

Conclusion

In this post, I showed how we can implement Controller Advice - exception handler in Spring Boot. This is a very effective way to handle exceptions in the current applications built with Spring Boot.

    Share:
    Back to Blog

    Related Posts

    View All Posts »

    Building Saas in 2024

    A comprehensive guide to the technology stack and considerations for building a full-stack SaaS application in 2024.

    System Thinking

    Learn how to think in systems and apply systems thinking to software engineering and architecture decisions.

    How Databases Work

    How Databases Work

    An in-depth exploration of how databases work under the hood, from storage engines to query processing.