Master Unified Exception Handling in Spring: Replace try‑catch with Assertions and Enums

This article shows how to eliminate most try‑catch blocks in Java Spring applications by using @ControllerAdvice, custom assertion utilities, and enum‑driven error codes, providing a clean, internationalized error‑response format and even turning 404s into catchable exceptions.

Top Architect
Top Architect
Top Architect
Master Unified Exception Handling in Spring: Replace try‑catch with Assertions and Enums

Why try‑catch code becomes a problem

In large Java services developers spend a lot of time writing repetitive try { … } catch { … } blocks, which makes code noisy and hard to read.

Using assertions instead of explicit checks

Spring provides org.springframework.util.Assert for pre‑condition checks. For example, a test method can use:

@Test
public void test1() {
    User user = userDao.selectById(userId);
    Assert.notNull(user, "用户不存在.");
}

This is far cleaner than writing an

if (user == null) { throw new IllegalArgumentException("用户不存在."); }

block.

Designing a custom assertion framework

To avoid creating a separate exception class for every error scenario, the article proposes an Assert interface whose default methods delegate to a newException factory. An IResponseEnum interface defines int getCode() and String getMessage(). Business error codes are stored in an enum, e.g.:

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

Custom assertion methods then look like:

public interface BusinessExceptionAssert extends IResponseEnum, Assert {
    @Override
    default BaseException newException(Object... args) {
        String msg = MessageFormat.format(this.getMessage(), args);
        return new BusinessException(this, args, msg);
    }
}

Enum constants implement this interface, so throwing a specific error becomes as simple as:

ResponseEnum.LICENCE_NOT_FOUND.assertNotNull(licence);

Unified exception handling with @ControllerAdvice

A UnifiedExceptionHandler class annotated with @ControllerAdvice catches all exceptions thrown from controllers or services. It defines methods such as:

@ExceptionHandler(value = BusinessException.class)
@ResponseBody
public ErrorResponse handleBusinessException(BaseException e) {
    log.error(e.getMessage(), e);
    return new ErrorResponse(e.getResponseEnum().getCode(), getMessage(e));
}

Similar handlers exist for BaseException, generic Exception, and a large list of Spring MVC binding exceptions (e.g., NoHandlerFoundException, HttpRequestMethodNotSupportedException, BindException, MethodArgumentNotValidException). The handler extracts a user‑friendly message using a UnifiedMessageSource that supports internationalization.

Making 404 an exception

By default Spring forwards a 404 to /error. Adding the following properties forces Spring to throw NoHandlerFoundException instead:

spring.mvc.throw-exception-if-no-handler-found=true
spring.resources.add-mappings=false

Now the handleServletException method can return a structured error response for missing URLs.

Standard response payloads

The article defines a base response class BaseResponse with code and message fields, and subclasses CommonResponse (adds data) and QueryDataResponse (adds pagination fields). For convenience, short wrappers R<T> and QR<T> are introduced, allowing controllers to return new R<>(data) or new QR<>(queryData).

Verification example

A sample LicenceService demonstrates the workflow: fetching a licence, asserting its existence with ResponseEnum.LICENCE_NOT_FOUND.assertNotNull(licence), and returning DTOs wrapped in R or QR. Various test cases show how the unified handler returns proper JSON with code and message for missing resources, bad licence types, validation errors, unsupported HTTP methods, and unexpected database errors.

Production‑environment considerations

When the active Spring profile is prod, the handler hides technical details and returns generic messages such as SERVER_ERROR to avoid exposing stack traces to end users.

Key takeaways

By combining assertions, enum‑based error codes, and a centralized @ControllerAdvice component, developers can dramatically reduce boilerplate try‑catch code, achieve consistent error responses, and simplify internationalization across a Spring‑based backend.

backendJavaException HandlingSpringEnumAssertionsUnified API
Top Architect
Written by

Top Architect

Top Architect focuses on sharing practical architecture knowledge, covering enterprise, system, website, large‑scale distributed, and high‑availability architectures, plus architecture adjustments using internet technologies. We welcome idea‑driven, sharing‑oriented architects to exchange and learn together.

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.