I want to customize DefaultHandlerExceptionResolver
in my Spring Boot application but custom implementation was never reached when exception was occurred.
build.gradle
buildscript {
ext {
springBootVersion = '2.1.1.RELEASE'
}
repositories {
mavenCentral()
}
}
plugins {
id 'java'
id 'org.springframework.boot' version '2.1.1.RELEASE'
id 'io.spring.dependency-management' version '1.0.6.RELEASE'
id 'io.franzbecker.gradle-lombok' version '1.14'
}
lombok {
version = '1.18.4'
sha256 = ""
}
group = 'ua.com.javaman'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = 1.8
repositories {
mavenCentral()
}
dependencies {
implementation('org.springframework.boot:spring-boot-starter-web')
}
Application.java
@SpringBootApplication
@RestController
@Configuration
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
@ResponseBody
@PostMapping("/mouse")
public Mouse postMouse(@Valid Mouse mouse) {
// mouse creation logic
return mouse;
}
@Bean
public HandlerExceptionResolver customHandlerExceptionResolver() {
return new CustomExceptionHandlerResolver();
}
}
Mouse.java
@Value
public class Mouse {
private final Long id;
@NotEmpty
@Min(2)
private final String name;
}
CustomExceptionHandlerResolver.java
public class CustomExceptionHandlerResolver extends DefaultHandlerExceptionResolver {
@Override
protected ModelAndView handleBindException(
BindException ex, HttpServletRequest request, HttpServletResponse response, @Nullable Object handler
) throws IOException {
System.out.println("In CustomExceptionHandlerResolver");
response.sendError(HttpServletResponse.SC_BAD_REQUEST);
return new ModelAndView();
}
}
Package structure
.
├── build.gradle
├── gradle
│ └── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── LICENSE
├── README.md
├── settings.gradle
└── src
└── main
└── java
└── ua
└── com
└── javaman
└── exception_handling
├── Application.java
├── CustomExceptionHandlerResolver.java
└── Mouse.java
When I invoke application with wrong values for Mouse
entity, for example,
POST localhost:8080/mouse?name=1
than handleBindException()
method in DefaultHandlerExceptionResolver
is invoked but not in my CustomExceptionHandlerResolver
.
How can I handle BindException
with my CustomExceptionHandlerResolver
?
Method SummaryHandle the case where an async request timed out. Handle the case where an @ModelAttribute method argument has binding or validation errors and is not followed by another method argument of type BindingResult . Handle the case when a WebDataBinder conversion cannot occur.
Exception HandlerThe @ExceptionHandler is an annotation used to handle the specific exceptions and sending the custom responses to the client. Define a class that extends the RuntimeException class. You can define the @ExceptionHandler method to handle the exceptions as shown.
In Java, exception handling is done by try, catch blocks but spring boot also allows us to provide customized global exception handling where we need not to add try catch block everwhere, we can create a separate class for handling exceptions and it also separates the exception handling code from businesss logic code.
@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.
Spring MVC may throw a number of exceptions internally while processing a request. These exceptions are handled by DefaultHandlerExceptionResolver. The important aspect of this resolver is, it translates the internal exception to specific HTTP status codes.
If these functions are developed without perfect processing of exception capture or even the logic itself exists BUG, it may lead to the exception not being properly captured and processed, and the default exception handler DefaultErrorWebExceptionHandler, the processing logic of the default exception handler may not meet our expected results.
Can I customize the logic of a process builder as below? Yes, You can add this in the process builder.
DefaultErrorWebExceptionHandler#getHttpStatus () is a wrapper for the response status code, the original logic is based on the status attribute of the exception property getErrorAttributes () for parsing. The custom JsonErrorWebExceptionHandler is as follows.
SpringBoot 's auto configuration will always create a bunch of exception handlers by default which one of them is DefaultHandlerExceptionResolver
at order 0 (lower value has the higher priority) . Your handler by default will has lower priority than these default , so it will not be invoked as the exception is already handled by the default.
You can implement your configuration class with WebMvcConfigurer
and override extendHandlerExceptionResolvers() to modify the default settings. The idea is to find out the DefaultHandlerExceptionResolver
instance and replace it with yours.
But a better idea is to define your CustomExceptionHandlerResolver
with @ControllerAdvice
, which make sure that you will not mess up with the default settings while still add the customised behaviour that your want (i.e use your logic to handle BindException
) :
@Component
@ControllerAdvice
public class CustomExceptionHandlerResolver {
@ExceptionHandler(value= BindException.class)
@Override
protected ModelAndView handleBindException(
BindException ex, HttpServletRequest request, HttpServletResponse response, @Nullable Object handler)
throws IOException {
System.out.println("In CustomExceptionHandlerResolver");
response.sendError(HttpServletResponse.SC_BAD_REQUEST);
return new ModelAndView();
}
}
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