Spring Boot global controller advice is not loaded in Spring Context

spring boot controller advice
global exception handling in java
exception handling in spring boot microservices
responsestatusexception spring boot
controlleradvice not working
constraintviolationexception spring boot
controlleradvice vs restcontrolleradvice
spring boot 404 handler

I have a controller to receive POST requests and return a JSON output. An exception handler which was implemented inside the controller class worked fine.

I have tried to add Global exception handling with @ControllerAdvice annotation, but this doesn't work in my solution. I don't think the global exception handler class is being loaded.

Below is my controller class:

package hello;

@Controller
@RequestMapping("/v1")
public class MyController {

  @RequestMapping(value = "/saveEmployee", method = RequestMethod.POST, produces = "application/json")
  @ResponseBody
  public String saveEmployee(@Valid @RequestBody Employee employee) {
    return "{ \"name\":\"" + employee.getEmail() + "\"}";
  }
}

Below is Global exception handler class:

package util;

@ControllerAdvice
public class MyControllerAdvice {

  @ExceptionHandler(MethodArgumentNotValidException.class)
  // @ResponseStatus(HttpStatus.BAD_REQUEST)
  @ResponseBody
  public String processValidationError(MethodArgumentNotValidException ex) {
    BindingResult result = ex.getBindingResult();
    FieldError fieldError = result.getFieldError();
    String code = fieldError.getCode();
    String field = fieldError.getField();
    String message = fieldError.getDefaultMessage();
    message = "{ \"Code\":\"" + code + "\",\"field\":\"" + field + "\",\"Message\":\"" + message + "\"}";
    return message;
  }
}

Below are my configurations:

package hello;

@SpringBootApplication
public class Application {

    @Bean
    public MessageSource messageSource() {
        ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
        messageSource.setBasename("classpath:messages");
        messageSource.setDefaultEncoding("UTF-8");
        return messageSource;
    }

    @Bean
    public LocalValidatorFactoryBean validator() {
        LocalValidatorFactoryBean bean = new LocalValidatorFactoryBean();
        bean.setValidationMessageSource(messageSource());
        return bean;
    }

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

Spring boot version : 2.0.3.RELEASE

I think the problem you have here is exactly what you identified. The MyControllerAdvice class isn't being loaded. From the code you posted, I'm inferring that your project structure looks something like:

src
  main
    java
      hello
        Application.java
        MyController.java
      util
        MyControllerAdvice.java

Because you have the SpringBootApplication annotation on your Application class, Spring Boot uses that as its starting point for creating beans, and it looks for classes annotated with things like @Controller and @ControllerAdvice (among others) to add to its context.

There are many different ways to configure that, but the simplest if you're starting out or working with a relatively small project, will be to restructure it to fit Spring's recommendation here:

https://docs.spring.io/spring-boot/docs/current/reference/html/using-boot-structuring-your-code.html

That page is very short and worth reading to get the background, but the essence is that you want your @SpringBootApplication annotated class in the same package or a parent package as all the classes you want Spring to manage, the page above gives the following example:

com
 +- example
   +- myapplication
     +- Application.java
     |
     +- customer
     | +- Customer.java
     | +- CustomerController.java
     | +- CustomerService.java
     | +- CustomerRepository.java
     |
     +- order
       +- Order.java
       +- OrderController.java
       +- OrderService.java
       +- OrderRepository.java

So, in your case, this would mean either moving the util package under hello, like:

src
  main
    java
      hello
        Application.java
        MyController.java
        util
          MyControllerAdvice.java

Or creating a parent package for both hello and util and moving Application up to that package, like:

src
  main
    java
      example
        Application.java
        hello
          MyController.java
        util
          MyControllerAdvice.java

Spring Boot global controller advice is not loaded in Spring Context, I think the problem you have here is exactly what you identified. The MyControllerAdvice class isn't being loaded. From the code you posted,  In the following Spring Boot application we use @ControllerAdvice to handle three exceptions: when a city is not found, when there is no data, and when a data for a new city to be saved is not valid.

try this: @ControllerAdvice("hello")

According to the documentation of ControllerAdvice:

Controllers that belong to those base packages or sub-packages thereof will be included, e.g.: @ControllerAdvice(basePackages="org.my.pkg") or @ControllerAdvice(basePackages={"org.my.pkg", "org.my.other.pkg"}). value is an alias for this attribute, simply allowing for more concise use of the annotation. Also consider using basePackageClasses() as a type-safe alternative to String-based package names.

Global Exception Handling With @ControllerAdvice, @ControllerAdvice is an annotation provided by Spring allowing you to write global code if you do not wish to use this class, spring-boot-start-web will be sufficient and will still import org.springframework.boot.context.event. files which are then loaded with Spring's configuration property mechanism. Yes, Spring Boot as a host of very cool features and options for configuration – these are just a few of the more common and useful ones, but certainly not a replacement for the standard reference. That being said – I might write another article about these – as they do come up often enough.

Are you sure it throws MethodArgumentNotValidException? Make the default handler like this

@ExceptionHandler(value = {Exception.class})
public ResponseEntity<Object> exception(Exception exception) {
    return new ResponseEntity<>(exception, HttpStatus.BAD_REQUEST)
}

Global exception handling with @ControllerAdvice, spring-boot-starter-hateoas is included to allow VndErrors to be used, if you do not wish to use this class spring-boot-starter-web will be sufficient  I have checked most similar questions, and don't find the answer.So I can only post a new question. I can successfully run my application without errors, but the rest api I write can't be access

Spring Boot - Exception Handling, to a chosen package or even a specific annotation. The @ControllerAdvice annotation was first introduced in Spring 3.2. It allows you to handle exceptions across the whole application, not just to an individual controller.

Global Exception Handler, Framework version: 1.1 Implementations: Spring Boot Scenario Controller throws an exception and ControllerAdvice will transform the exception into Spring Boot from loading your @ControllerAdvice -annotated class? My understanding is that as long as there’s a commandLineRunner in the spring context, it’ll get executed. But I don’t know if that’s correct. I’m also interested to know the running or initialisation order of the things in spring.

@ControllerAdvice does not work · Issue #167 · awslabs/aws , Exception Handling for a REST API - illustrate the Spring 3.2+ Since 3.2 we've had the @ControllerAdvice annotation to address the Finally, we'll see what Spring Boot brings to the table, and how we can configure it to suit our needs. for that particular Controller, not globally for the entire application. The SimpleMappingExceptionResolver has been around for quite some time – it comes out of the older Spring MVC model and is not very relevant for a REST Service. We basically use it to map exception class names to view names.

Comments
  • This is what i receive in invalid parameter passing to the controller "[nio-8080-exec-2] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved exception caused by Handler execution: org.springframework.web.bind.MethodArgumentNotValidException: Validation failed for argument at index 0 in method:"@Piotr Rogowski
  • Can you post your Spring configuration for the said controllers? I'm seeing that the controller is in a package called hello whereas the exception handler in a package called util. My first though is that you're not bringing the exception handler into context.
  • Yes. This works. I've re structured the entire project.Now the Spring boot has added @ControllerAdvice to the context. Thanks
  • I've already tried this. But no difference.What i observe is "DefaultHandlerExceptionResolver : Resolved exception caused by Handler execution: org.springframework.web.bind.MethodArgumentNotValidException:"@Hank
  • Try put MyControllerAdvice to the same package of MyController. I could reproduce your problem and fix it by my solution, both.
  • Yes. I just tried the same as you mentioned and that worked. Thanks. But do you identify any reason to not to work MyControllerAdvice in a different package ? @Hank
  • @DaveyDaveDave's answer explains my point. Spring use the package of @SpringBootApplication class as default root package and scan Beans/Configurations under that root package. That's why your @ControllerAdvice is not found by Spring at the beginning :). But please also note that, just pulling @SpringBootApplication to upper level is not enough, @ControllerAdvice effects the same package (and sub packages) of @Controller only by default, except you config basePackages correctly.
  • Yes. It was a great advice. I configured the base package correctly and sorted the issue.@Hank
  • No. This doesn't work. Yes i'm sure that it it fires a MethodArgumentNotValidException @GerNik