History of a bug

Spring @ControllerAdvice order and precedence

Rédigé par gorki Aucun commentaire

Problem :

I added a second @ControllerAdvice to handle my 404 pages in addition to an existing @ControllerAdvice that was handling a REST Api for the backend part.

My newer controller advice has : 

    public ModelAndView handleError404(HttpServletRequest request, Exception e) {
        if (request.getRequestURI().startsWith("/api")) {
            throw new ResourceNotFoundException();
        } else {
            ModelAndView mv = new ModelAndView();
            return mv;

The existing one has : 

    public ErrorDTO handleException(Exception e) {
        log.error(e.getMessage(), e);
        return new ErrorDTO(e.getMessage(), "E01");

On dev environment, it works.

On production environment, it fails : only the REST API exception handler was used.

A remote debug show me that I was in : @ExceptionHandler(Exception.class)

the general exception handler, and the exception thrown is NoHandlerFoundException

Solution :

I tried this solution : 

  • Use @Order on each class
  • as seen here

But it also fails and as noted in the answers : 

I also found in the documentation that :



protected ServletInvocableHandlerMethod getExceptionHandlerMethod(HandlerMethod handlerMethod, Exception exception)

Find an @ExceptionHandler method for the given exception. The default implementation searches methods in the class hierarchy of the controller first and if not found, it continues searching for additional @ExceptionHandler methods assuming some @ControllerAdvice Spring-managed beans were detected. Parameters: handlerMethod - the method where the exception was raised (may be null) exception - the raised exception Returns: a method to handle the exception, or null

So I merged the both classes and it works.

But it's not really clear : 

  • Older exception handler is not in the class hierarchy
  • I did not check if my latest exception handler was well detected on production (code is the same and it works in dev)

So not yet the final word, but too late for today :)




Fil RSS des articles de ce mot clé