Order of @ExceptionHandler

2020-06-09 07:54发布

问题:

I use @ControllerAdvice to handle all my app exceptions :

@ControllerAdvice
public class ExceptionHandlingController {

  @ExceptionHandler({UnauthorizedException.class})
  public String unauthorizedException()  {
        .........
  }


  @ExceptionHandler({UnauthorizedAjaxException.class})
  @ResponseBody
  public void unauthorizedAjaxException()  {
        .........
  }

  @ExceptionHandler({Exception.class})
  public String globalException(){
        .........
  }


}

And somewhere in my code i do throw new UnauthorizedException();

   @Around("@annotation(Authenticated)")
   public Object profilingAuthentication(ProceedingJoinPoint pjp) throws Throwable  {

       HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();

       if( request.getSession().getAttribute("idContact") == null ) {
            if( "XMLHttpRequest".equals(request.getHeader("X-Requested-With")) )
                throw new UnauthorizedAjaxException();
            throw new UnauthorizedException();
       } 
       return pjp.proceed();
   }

But sadly Spring MVC appears to be acting random by using the most generic case (Exception) rather than more specific ones (UnauthorizedException for example). And sometimes he choose the correct one !

How the order works works ? and is there any way to specify the order ?

UnauthorizedException is a custom exception

public class UnauthorizedException extends Exception {

    public UnauthorizedException(){
        super();
    }

    public UnauthorizedException(String message){
        super(message);
    }
}

UPDATE

i found out that the order it's not rondom actually the methods who throw UnauthorizedException works normally but the others not !

@Authenticated
@RequestMapping(value="/favoris") 
public String favoris(ModelMap model, HttpServletRequest request) 
      throws UnauthorizedException {
    ....
}

@Authenticated
@RequestMapping(value="/follow") 
public String follow(ModelMap model, HttpServletRequest request) {
    .....
}

So i have to add throws UnauthorizedException manually or there is some other solution ?

回答1:

we are using exception handler in following way and never order get mixed and it work as expected. So it could be possible if you will use it as following example then it will solve your problems

**********handler class******************

@ControllerAdvice
public class GlobalExceptionHandler {

    @ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
    @ExceptionHandler(value = Exception.class)
    public boolean handle1(Exception exc) {
        System.out.println("#####Global Exception###" + exc);
        exc.printStackTrace(System.out);
        return true;
    }

    @ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
    @ExceptionHandler(value = CustomException.class)
    public boolean handle2(CustomException exc) {
        System.out.println("###custom exception######" + exc);
        exc.printStackTrace(System.out);
        return true;
    }
}

***************Controller class************

@RestController("test")
@RequestMapping("/test1")
public class TestController {

    @RequestMapping("/t1")
    public boolean test() {
        if (true) {
            throw new CustomException();
        }
        return true;
    }
}

In above example exception habdler is handle2 because 1st of all it will search for matching exception if not found then go for parrent handler

If we throw new NullPointerException() then it will search for matching handler but not found in this case then go for parrent that is handle1

for more you can refer here

I hope it will help you. Thanks



回答2:

Use an annotation @Order or implement an interface Ordered for @ControllerAdvice.

See implementations of:

  • ExceptionHandlerMethodResolver class
  • ExceptionHandlerExceptionResolver class (method initExceptionHandlerAdviceCache)
  • AnnotationAwareOrderComparator class


回答3:

There is no order/priority as long as you have a single controlleradvice class in your project. But if you have multiple controlleradvice classes, you can set the Order. But here, in your case, the order is not applicable as the two exceptions are handled differently (i.e., UnauthorizedException and Exception).

The good thing is, Spring will automatically find the respective custom Exception class (if any, otherwise generic Exception) and invoke the corresponding method.

Please refer for more information on Spring Controller Advice and Exception handling: https://spring.io/blog/2013/11/01/exception-handling-in-spring-mvc