Search code examples
javaspringspring-mvcexceptionspring-aop

How to handle exception thrown from ExceptionHandler in controller with ExceptionHandler in ControllerAdvice?


I have custom Exceptions extending Exception (MyException1, MyException2, MyException3)

@Controller
public class MyController {
    /*
       Method throwing MyException1
       Method throwing MyException2
       Method throwing MyException3
    */

    @ExceptionHandler(MyException1.class)
    public void handleMyException1(Exception ex){
        //Do something
        throw ex;
    }
    @ExceptionHandler(MyException2.class)
    public void handleMyException2(Exception ex){
        System.out.println("Exception Logged inside Controller")
    }
}

@ControllerAdvice
public class MyGlobalExceptionHandler {
    @ExceptionHandler(Exception.class)
    public void handleAllException(Exception ex){
        System.out.println("Exception logged Outside Controller");
    }
}

My Intention:

  • log MyException1 from controller advice
  • log MyException2 inside handler in controller itself
  • log MyException3 from controller advice

MyException2 and MyException3 are working as intended, but MyException1 fails with:

Failed to invoke @ExceptionHandler method .....handleMyException1


Solution

  • You can pick one of the following options for your exception handling:

    Option(1) : Remove @ExceptionHandler(MyException1.class) method from Controller so that it will be automatically handled by MyGlobalExceptionHandler.

    Option(2) : Create MyException4 (which is a Wrapper for MyException1 with added information) & throw it from Controller as shown below:

    @Controller
    public class MyController {
        /*
           Method throwing MyException1
           Method throwing MyException2
           Method throwing MyException3
        */
    
        @ExceptionHandler(MyException1.class)
        public void handleMyException1(Exception ex){
             //MyException4 exe4 = new MyException4();
            // Add the required details to it
            throw exe4;
        }
    
        @ExceptionHandler(MyException2.class)
        public void handleMyException2(Exception ex){
            System.out.println("Exception Logged inside Controller")
        }
    }
    
    @ControllerAdvice
    public class MyGlobalExceptionHandler {
        @ExceptionHandler(Exception.class)
        public void handleAllException(Exception ex){
            System.out.println("Exception logged Outside Controller");
        }
    }
    

    P.S.: I did not add Option(3) here, which is manually invoking MyGlobalExceptionHandler's handleAllException() as It is not a good practice. Rather you should simply throw the exception and the @ExceptionHandler will take care automatically.

    One more problem with the manual invocation is that at some point of time in future, it will be problematic to debug the exceptions as some of your flows manually call MyGlobalExceptionHandler and some flows are called by the framework.