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
@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.
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.
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.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With