Unified Exception Handling in Spring Using @ControllerAdvice, Assert Utilities, and Enum‑Based Error Definitions
This article explains how to implement a unified exception handling mechanism in Spring applications by using @ControllerAdvice, custom Assert utilities, and enum‑based error definitions to replace repetitive try‑catch blocks, improve code readability, and provide consistent error responses across controllers and services.
The article starts by describing the problem of excessive try { ... } catch { ... } finally { ... } blocks in Java services, which lead to redundant code and poor readability.
It introduces Spring's @ControllerAdvice annotation (available since Spring 3.2) as a way to apply exception handlers globally, avoiding the need to repeat @ExceptionHandler methods in each controller.
To further reduce boilerplate, the author proposes using an Assert utility (similar to org.springframework.util.Assert ) that throws custom business exceptions when validation fails. The utility is defined as an interface with default methods such as assertNotNull(Object obj) and assertNotNull(Object obj, Object... args) , delegating exception creation to two newException methods.
Custom exceptions are modeled with a BaseException that carries an error code and message. An IResponseEnum interface defines getCode() and getMessage() , and a BusinessExceptionAssert interface extends both IResponseEnum and Assert . Implementations of BusinessExceptionAssert (e.g., ResponseEnum ) provide concrete enum constants such as BAD_LICENCE_TYPE and LICENCE_NOT_FOUND , each mapping to a specific error code and message.
The unified exception handler class is annotated with @ControllerAdvice , @Component , and conditional annotations to ensure a single instance. It defines handlers for:
@ExceptionHandler(BusinessException.class) – handles custom business exceptions.
@ExceptionHandler(BaseException.class) – handles other framework‑defined exceptions.
@ExceptionHandler({NoHandlerFoundException.class, HttpRequestMethodNotSupportedException.class, ...}) – handles servlet‑level errors occurring before controller execution.
@ExceptionHandler(BindException.class) and @ExceptionHandler(MethodArgumentNotValidException.class) – aggregate validation errors into a single message.
@ExceptionHandler(Exception.class) – catches all unknown exceptions, optionally masking details in production environments.
Each handler logs the error, determines an appropriate error code (often via enums like CommonResponseEnum.SERVER_ERROR or ServletResponseEnum ), retrieves a localized message if needed, and returns an ErrorResponse object containing code and message .
The article also shows how to configure Spring to throw exceptions for 404 errors ( spring.mvc.throw-exception-if-no-handler-found=true ) and demonstrates the whole flow with a sample LicenceService that uses the enum‑based asserts to validate inputs and retrieve data.
Finally, the author summarizes that combining assertions, enums, and a global @ControllerAdvice handler can dramatically reduce boilerplate, centralize error handling, and produce consistent API responses, while also supporting internationalization of error messages.
Java Architect Essentials
Committed to sharing quality articles and tutorials to help Java programmers progress from junior to mid-level to senior architect. We curate high-quality learning resources, interview questions, videos, and projects from across the internet to help you systematically improve your Java architecture skills. Follow and reply '1024' to get Java programming resources. Learn together, grow together.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.