Elegant Exception Handling in Spring: Unified @ControllerAdvice, Assertions, and Enum‑Based Errors

The article demonstrates how to replace scattered try‑catch blocks with a clean, unified exception handling strategy in Spring, using @ControllerAdvice, custom BaseException, enum‑driven error codes, and Assert utilities, while also standardizing API responses and handling common MVC errors such as 404.

SpringMeng
SpringMeng
SpringMeng
Elegant Exception Handling in Spring: Unified @ControllerAdvice, Assertions, and Enum‑Based Errors

In large Java projects, developers often end up with noisy try { … } catch { … } finally { … } blocks that hurt readability. The author first shows a typical messy controller method and then proposes a systematic approach that moves all error handling to a single place.

Unified Exception Handling with @ControllerAdvice

Spring 3.2 introduced @ControllerAdvice which can be combined with @ExceptionHandler to intercept exceptions thrown from any @Controller. The article defines a UnifiedExceptionHandler class annotated with @ControllerAdvice, @Component, and conditional beans to ensure it is loaded only once.

@Slf4j
@Component
@ControllerAdvice
@ConditionalOnWebApplication
@ConditionalOnMissingBean(UnifiedExceptionHandler.class)
public class UnifiedExceptionHandler {
    // ... environment detection, message source, handlers ...
}

Inside the handler, the code distinguishes three main exception groups:

Controller‑stage exceptions (e.g., NoHandlerFoundException, HttpRequestMethodNotSupportedException, MissingPathVariableException) are processed by handleServletException.

Business exceptions extending BaseException are handled by handleBusinessException and handleBaseException.

Unknown exceptions fall back to handleException, which returns a generic error response.

Custom Exception Hierarchy

The author defines a lightweight BaseException that carries an IResponseEnum (an enum with code and message) and optional arguments. Specific business errors are expressed as enum constants, for example:

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

Each enum implements assertNotNull(Object obj) (and overloaded variants) that throw a BusinessException with the corresponding enum, eliminating the need for a separate exception class per error scenario.

Assertion Utility

Instead of manual

if (obj == null) { throw new IllegalArgumentException(...); }

, the article recommends using Spring's Assert (or the custom enum‑based assert) to make the code concise and expressive:

public void checkNotNull(Licence licence) {
    ResponseEnum.LICENCE_NOT_FOUND.assertNotNull(licence);
}

This pattern is demonstrated in service methods such as queryDetail(Long licenceId) and getLicences(LicenceParam licenceParam), where null checks and enum validation replace verbose if statements.

Standardized API Response

All controllers return a unified response structure. The base class BaseResponse contains code and message. Two concrete subclasses are used: CommonResponse<T> adds a data field for successful payloads. ErrorResponse represents error results.

For brevity the author introduces shortcut classes R<T> and QR<T> that extend the above and can be instantiated as new R<>(data) or new QR<>(queryData).

Handling Spring MVC Errors (404, 405, Validation)

The handler covers many built‑in Spring MVC exceptions, explaining the circumstances that trigger each one (missing handler, unsupported HTTP method, missing path variable, type mismatch, unreadable request body, etc.). For example, handleServletException extracts a custom error code from an enum mapping and returns a generic SERVER_ERROR in production environments.

Internationalization

When building the error message, the handler looks up a localized message using UnifiedMessageSource.getMessage(code, args). If no translation is found, the original exception message is used.

Testing the Strategy

The article includes a small demo service ( LicenceService) that uses the unified assertions and shows how various error scenarios are captured:

Requesting a non‑existent licence ID triggers LICENCE_NOT_FOUND.

Providing an invalid licence type triggers BAD_LICENCE_TYPE.

Calling an undefined URL returns a NoHandlerFoundException that is turned into a 404 response.

Invalid request bodies cause MethodArgumentNotValidException and are formatted into a single error string.

Adding an unmapped column to the entity demonstrates the fallback handleException path.

All responses follow the {"code":…, "message":…, "data":…} format, making the front‑end handling uniform.

Production‑Specific Behaviour

When the active Spring profile equals prod, the handler suppresses technical details and returns a generic "Network error" or "Server error" message, preventing internal stack traces from leaking to end users.

Conclusion

By combining @ControllerAdvice, a small enum‑based error catalog, and assertion helpers, developers can eliminate repetitive try‑catch blocks, keep controller code clean, and guarantee that every exception is transformed into a consistent, internationalized API response.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

backendjavaException HandlingSpringEnumAssertions
SpringMeng
Written by

SpringMeng

Focused on software development, sharing source code and tutorials for various systems.

0 followers
Reader feedback

How this landed with the community

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.