Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

275
Visualizações
Spring: Different exception handler for RestController and Controller

In Spring you can set up "global" exception handler via @ControllerAdvice and @ExceptionHandler annotation. I'm trying to utilize this mechanism to have two global exception handlers:

  • RestControllerExceptionHandler - which should return error responses as json for any controller annotated with @RestController
  • ControllerExceptionHandler - which should print error message to the screen for any other controller (annottated with @Controller)

The problem is that when I declare these two exception handlers spring always uses the ControllerExceptionHandler and never RestControllerExceptionHandler to handle the exception.

How to make this work ? BTW: I tried to use @Order annotation but this does not seem to work.

Here are my exception handlers:

// should handle all exception for classes annotated with         
@ControllerAdvice(annotations = RestController.class)
public class RestControllerExceptionHandler {


  @ExceptionHandler(Exception.class)
  public ResponseEntity<ErrorResponse> handleUnexpectedException(Exception e) {

    // below object should be serialized to json
    ErrorResponse errorResponse = new ErrorResponse("asdasd"); 

    return new ResponseEntity<ErrorResponse>(errorResponse, HttpStatus.INTERNAL_SERVER_ERROR);
  }

// should handle exceptions for all the other controllers
@ControllerAdvice(annotations = Controller.class)
public class ControllerExceptionHandler {


  @ExceptionHandler(Exception.class)
  public ResponseEntity<String> handleUnexpectedException(Exception e) {
    return new ResponseEntity<String>("Unexpected exception, HttpStatus.INTERNAL_SERVER_ERROR);
  }


}
}

When I remove ControllerExceptionHandler than RestControllerExceptionHandler is correctly called by spring (only for classes annotated with @RestController).... but when I add ControllerExceptionHandler than all goes via ControllerExceptionHandler. Why?

about 4 years ago · Santiago Trujillo
3 Respostas
Responde à pergunta

0

After some deeper investigation it seems that the alphabetical order matters :/.

When I renamed my RestControllerExceptionHandler to ARestControllerExceptionHandler (which alphabetically precedes ControllerExceptionHandler) all works as expected! ARestControllerExceptionHandler correctly handles exceptions from RestControllers and ControllerExceptionHandler handles exception from other controllers.

I created a bug in spring for this: https://jira.spring.io/browse/SPR-15432

--- EDIT:

I received the answer for SPR-15432 where it is suggested that this case can be solved with @Order (org.springframework.core.annotation.Order) annotation or by implementing Ordered interface.

This did not work for me before, but it seems that I have imported wrong @Order annotation. (from log4j2 instead of spring). After fixing this it works. Fixed version is following:

// should handle all exception for classes annotated with         
@ControllerAdvice(annotations = RestController.class)
@Order(1) // NOTE: order 1 here
public class RestControllerExceptionHandler {


  @ExceptionHandler(Exception.class)
  public ResponseEntity<ErrorResponse> handleUnexpectedException(Exception e) {

    // below object should be serialized to json
    ErrorResponse errorResponse = new ErrorResponse("asdasd"); 

    return new ResponseEntity<ErrorResponse>(errorResponse, HttpStatus.INTERNAL_SERVER_ERROR);
  }
}
// should handle exceptions for all the other controllers
@ControllerAdvice(annotations = Controller.class)
@Order(2)  // NOTE: order 2 here
public class ControllerExceptionHandler {


  @ExceptionHandler(Exception.class)
  public ResponseEntity<String> handleUnexpectedException(Exception e) {
    return new ResponseEntity<String>("Unexpected exception, HttpStatus.INTERNAL_SERVER_ERROR);
  }
}
about 4 years ago · Santiago Trujillo Relatório

0

That's happening because @RestController annotation is itself an @Controller as well so Spring is considering the @ControllerAdvice with annotation = Controller.class for both.

You may try another method to define the subset of Controllers that the @ControllerAdvice will have effect, so here are some solutions:


Solution 1

  1. Create a new Annotation @NotRestController:

    @Target({ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
        public @interface NotRestController {
    }
    
  2. Mark controllers that are not @RestController with both @Controller and @NotRestController:

    @Controller
    @NotRestController
    @RequestMapping("/controller")
    public class SampleController {
    }
    
  3. Use NotRestController.class on ControllerExceptionHandler:

    @ControllerAdvice(annotations = NotRestController.class)
    public class ControllerExceptionHandler {
    

I've created a sample project with Solution 1 and shared it on Github:

https://github.com/brunocleite/springexceptionhandlertest


Solution 2

  1. Move your @RestController classes into a package foo.bar and your @Controller classes into another package foo.nuk.

  2. Use basePackages property of @ControllerAdvice instead of annotations:

    @ControllerAdvice(basePackages={"foo.bar"})
    public class RestControllerExceptionHandler {
    
    @ControllerAdvice(basePackages={"foo.nuk"})
    public class ControllerExceptionHandler {
    

Best regards!

about 4 years ago · Santiago Trujillo Relatório

0

This was my solution. It eliminates the need to create additional annotations.

  1. Create 2 base controllers.
@Controller
public class BaseController

@Controller
public class BaseRestController
  1. Extend each controller with chosen base controller.
@Controller
public class UserController extends BaseController

@RestController
public class UserRestController extends BaseRestController
  1. Create 2 global controllers and include only the extended base class in each.
@ControllerAdvice(assignableTypes = BaseController.class)
public class GlobalController

@ControllerAdvice(assignableTypes = BaseRestController.class)
public class GlobalRestController
about 4 years ago · Santiago Trujillo Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda