Backend Development 22 min read

Unified Exception Handling in Spring: Using @ControllerAdvice, Assert, and Enum for Clean Code

This article explains how to replace repetitive try‑catch blocks in Java Spring applications with a unified exception handling mechanism that leverages @ControllerAdvice, custom Assert utilities, and an enum‑based error‑code system to produce clean, maintainable backend code.

Selected Java Interview Questions
Selected Java Interview Questions
Selected Java Interview Questions
Unified Exception Handling in Spring: Using @ControllerAdvice, Assert, and Enum for Clean Code

Background – In typical Java projects a large amount of boilerplate try { … } catch { … } finally { … } code appears, especially in Controllers and Services, which hurts readability.

The author compares an ugly try‑catch style with a clean Controller design and argues for moving exception handling out of business code.

What is Unified Exception Handling?

Since Spring 3.2 the @ControllerAdvice annotation can be combined with @ExceptionHandler , @InitBinder , and @ModelAttribute to apply exception handling globally.

Only @ExceptionHandler actually deals with exceptions. By defining a single class annotated with @ControllerAdvice , you can catch all controller‑level and service‑level exceptions in one place.

Goal

Eliminate more than 95% of explicit try‑catch blocks by using an Assert (assertion) style that throws custom business exceptions, allowing developers to focus on business logic.

Practical Implementation

1. Assert Replacement – Use Spring's org.springframework.util.Assert (or a custom one) to replace manual if (obj == null) { throw new … } checks.

@Test
public void test1() {
    User user = userDao.selectById(userId);
    Assert.notNull(user, "User does not exist.");
}

public void test2() {
    User user = userDao.selectById(userId);
    if (user == null) {
        throw new IllegalArgumentException("User does not exist.");
    }
}

The custom Assert interface defines newException methods so that the thrown exception can be a domain‑specific BusinessException with an error code and message.

public interface Assert {
    BaseException newException(Object... args);
    BaseException newException(Throwable t, Object... args);
    default void assertNotNull(Object obj) {
        if (obj == null) {
            throw newException(obj);
        }
    }
    default void assertNotNull(Object obj, Object... args) {
        if (obj == null) {
            throw newException(args);
        }
    }
}

Business exceptions are defined by an enum that implements BusinessExceptionAssert (which extends IResponseEnum and Assert ), e.g.:

public enum ResponseEnum implements BusinessExceptionAssert {
    BAD_LICENCE_TYPE(7001, "Bad licence type."),
    LICENCE_NOT_FOUND(7002, "Licence not found.");
    private int code;
    private String message;
}

Using the enum you can write concise validation code such as:

ResponseEnum.LICENCE_NOT_FOUND.assertNotNull(licence);
ResponseEnum.BAD_LICENCE_TYPE.assertNotNull(licenceTypeEnum);

Unified Exception Handler Class

The UnifiedExceptionHandler class is annotated with @ControllerAdvice and defines several @ExceptionHandler methods:

handleBusinessException – catches BusinessException .

handleBaseException – catches other custom BaseException s.

handleServletException – catches framework exceptions such as NoHandlerFoundException , HttpRequestMethodNotSupportedException , etc., and maps them to a generic error code in production.

handleBindException and handleValidException – process parameter‑binding and validation errors, aggregating field messages.

handleException – a fallback for any unknown exception, returning a generic server‑error response (or a user‑friendly "Network error" in production).

Each handler logs the exception, obtains a localized message via UnifiedMessageSource , and returns an ErrorResponse containing code and message .

Exception Classification

Exceptions are divided into two major groups:

Pre‑Controller exceptions (e.g., 404, method not allowed, missing parameters) handled by handleServletException .

Service‑level exceptions – custom business exceptions handled by handleBusinessException / handleBaseException and unknown exceptions handled by handleException .

Testing the Mechanism

Various scenarios are demonstrated: missing licence, invalid licence type, 404, unsupported HTTP method, parameter validation failures, and database errors caused by a mismatched entity field. All cases return a JSON payload with code and message .

Conclusion

By combining assertions, an enum‑based error‑code system, and a global @ControllerAdvice handler, most exceptions become easy to manage, the code stays clean, and the API returns consistent error structures. The approach can be packaged as a common library and reused across projects.

backendJavaexception handlingSpringenumAssertControllerAdvice
Selected Java Interview Questions
Written by

Selected Java Interview Questions

A professional Java tech channel sharing common knowledge to help developers fill gaps. Follow us!

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.