How to customize DefaultHandlerExceptionResolver logic?
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
DefaultHandlerExceptionResolver is one of Spring MVC's built-in exception resolvers. Its job is to translate common framework exceptions into HTTP status codes, not to produce rich API error bodies. When teams want to change that behavior, the right answer is usually to add custom handling around it rather than to replace Spring defaults blindly.
What DefaultHandlerExceptionResolver Actually Does
Spring MVC resolves exceptions through an ordered chain. Several components may participate:
- methods annotated with
@ExceptionHandler - '
@ControllerAdviceor@RestControllerAdvice' - '
ResponseStatusExceptionResolver' - '
DefaultHandlerExceptionResolver' - custom
HandlerExceptionResolverbeans
DefaultHandlerExceptionResolver focuses on framework exceptions such as unsupported HTTP methods, missing parameters, or media-type mismatches. It mainly sets status codes and may leave the response body empty. That is why many REST APIs need customization on top of it.
Before changing anything, decide what you are trying to customize:
- status code mapping
- response body format
- logging behavior
- resolver order
The implementation path depends on that choice.
Prefer @RestControllerAdvice for API Response Bodies
If the real goal is "return consistent JSON for framework exceptions," start with @RestControllerAdvice. It is clearer than subclassing the default resolver and easier to test.
This does not modify DefaultHandlerExceptionResolver itself, but it often solves the business problem more cleanly.
Subclass the Resolver When You Need Framework-Level Control
If you specifically need to change how one of the built-in framework exceptions is handled, subclass DefaultHandlerExceptionResolver and override the matching handle... method.
Returning a non-null ModelAndView tells Spring that the exception has been handled. If you return null, later resolvers may still run.
Registering Order Explicitly
Resolver order matters. If your custom resolver runs too late, Spring's built-in resolver may already have handled the exception. If it runs too early, it may intercept exceptions you intended to leave to a controller advice.
One explicit way to control the chain is through WebMvcConfigurer.
Use this kind of registration sparingly. A resolver chain with unclear ordering becomes difficult to reason about after framework upgrades.
When ResponseEntityExceptionHandler Is Better
For REST APIs, extending ResponseEntityExceptionHandler is often the best middle ground. It already understands many MVC exceptions and lets you customize the HTTP body without writing directly to HttpServletResponse.
That approach is usually easier to maintain than overriding DefaultHandlerExceptionResolver, because the returned ResponseEntity is explicit and test-friendly.
Testing the Behavior
Exception customization should be covered by integration tests, not only unit tests. The key risks are chain order and response shape.
A test like this catches regressions where resolver order changes silently.
Common Pitfalls
The first mistake is trying to customize response bodies by replacing Spring's default resolver entirely. In most API projects, @RestControllerAdvice or ResponseEntityExceptionHandler is the simpler tool.
Another problem is unclear ordering. Exception handling bugs often come from the wrong resolver winning the chain rather than from incorrect business logic.
A third issue is writing to HttpServletResponse and still letting processing continue. Once your resolver writes and returns a handled ModelAndView, the chain should stop for that exception.
Finally, teams sometimes add custom logging in every resolver and end up logging the same failure multiple times. Decide which layer owns error logging and keep it consistent.
Summary
- Use
@RestControllerAdvicefirst when the goal is structured API error bodies. - Subclass
DefaultHandlerExceptionResolveronly when you need framework-level exception handling control. - Set resolver order explicitly so the right handler wins.
- Prefer
ResponseEntityExceptionHandlerwhen you want Spring-aware customization without manual response writing. - Verify behavior with integration tests that assert both status codes and response bodies.

