129 votes

Définition de la priorité des gestionnaires @ExceptionHandlers multiples de @ControllerAdvice

J'ai plusieurs classes annotées avec @ControllerAdvice, chacune avec une méthode @ExceptionHandler.

L'une gère l' Exception avec l'intention que si aucun gestionnaire plus spécifique n'est trouvé, celui-ci doit être utilisé.

Malheureusement, Spring MVC semble toujours utiliser le cas le plus générique (Exception) plutôt que des cas plus spécifiques (IOException par exemple).

Est-ce ainsi que l'on s'attend à ce que Spring MVC se comporte? J'essaie d'imiter un modèle de Jersey, qui évalue chaque ExceptionMapper (composant équivalent) pour déterminer à quelle distance le type déclaré qu'il gère est de l'exception qui a été lancée, et utilise toujours l'ancêtre le plus proche.

4voto

Joyal Joseph Points 84

Classe importante à gérer :

@Order(Ordered.HIGHEST_PRECEDENCE)
public class FunctionalResponseEntityExceptionHandler 
{
    private final Logger logger = LoggerFactory.getLogger(FunctionalResponseEntityExceptionHandler.class);

    @ExceptionHandler(EntityNotFoundException.class)
    public final ResponseEntity handleFunctionalExceptions(EntityNotFoundException ex, WebRequest request)
    {
        logger.error(ex.getMessage() + " " + ex);
        ExceptionResponse exceptionResponse= new ExceptionResponse(new Date(), ex.getMessage(),
                request.getDescription(false),HttpStatus.NOT_FOUND.toString());
        return new ResponseEntity<>(exceptionResponse, HttpStatus.NOT_FOUND);
    }
}

Autres exceptions avec faible priorité
@ControllerAdvice
public class GlobalResponseEntityExceptionHandler extends ResponseEntityExceptionHandler
{
    private final Logger logger = LoggerFactory.getLogger(GlobalResponseEntityExceptionHandler.class);

    @ExceptionHandler(Exception.class)
    public final ResponseEntity handleAllException(Exception ex, WebRequest request)
    {
        logger.error(ex.getMessage()+ " " + ex);
        ExceptionResponse exceptionResponse= new ExceptionResponse(new Date(), ex.toString(),
                request.getDescription(false),HttpStatus.INTERNAL_SERVER_ERROR.toString());
    }
}

3voto

pimlottc Points 658

Il y a une situation similaire couverte dans l'excellent article "Gestion des exceptions dans Spring MVC" sur le blog de Spring, dans la section intitulée Gestion des exceptions globales. Leur scénario consiste à vérifier les annotations ResponseStatus enregistrées sur la classe d'exception, et si elles sont présentes, à re-lancer l'exception pour permettre au framework de les gérer. Vous pourriez peut-être utiliser cette tactique générale - essayer de déterminer s'il existe un gestionnaire plus approprié et de re-lancer.

Alternativement, il existe d'autres stratégies de gestion des exceptions que vous pourriez envisager.

1voto

Si vous souhaitez séparer vos gestionnaires d'exceptions (comme moi), vous pouvez utiliser @Import pour le faire.

@ControllerAdvice
class MyCustomExceptionHandler {
  ...
}

@ControllerAdvice
class MyOtherCustomExceptionHandler {
  ...
}

@Import({MyCustomExceptionHandler.class, MyOtherCustomExceptionHandler.class})
@ControllerAdvice
@Order(Ordered.LOWEST_PRECEDENCE)
class ApplicationExceptionHandler{
  //Gestionnaires d'exceptions génériques
}

0voto

MrKiller21 Points 753

Le framework Spring trie les beans annotés avec @ControllerAdvice en utilisant OrderComparator.

Cependant, les méthodes @ExceptionHandler présentes au sein d'une seule classe sont triées en utilisant ExceptionDepthComparator.

Cela signifie qu'une solution de contournement possible est de placer toutes les méthodes @ExceptionHandler dans une seule classe.

@ControllerAdvice
class ExceptionHandler {

    @ExceptionHandler(IOException.class)
    ResponseEntity handleIOException() {
        ....
    }

    @ExceptionHandler(Exception.class)
    ResponseEntity handleException() {
        ....
    }
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X