Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring Boot global controller advice is not loaded in Spring Context

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

like image 671
Lahiru Wijesekara Avatar asked Aug 08 '18 05:08

Lahiru Wijesekara


People also ask

How do you implement controller advice?

@ControllerAdvice is a specialization of the @Component annotation which allows to handle exceptions across the whole application in one global handling component. It can be viewed as an interceptor of exceptions thrown by methods annotated with @RequestMapping and similar.

How do you handle exception globally in spring boot?

You can define the @ExceptionHandler method to handle the exceptions as shown. This method should be used for writing the Controller Advice class file. Now, use the code given below to throw the exception from the API. The complete code to handle the exception is given below.

How do you handle an exception in spring boot using annotations?

The exception handler method takes in an exception or a list of exceptions as an argument that we want to handle in the defined method. We annotate the method with @ExceptionHandler and @ResponseStatus to define the exception we want to handle and the status code we want to return.


1 Answers

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
like image 116
DaveyDaveDave Avatar answered Nov 06 '22 05:11

DaveyDaveDave