Global Exception Handling
Relevant source files
The following files were used as context for generating this wiki page:
- src/main/java/org/example/coding_convention/common/exception/GlobalExceptionHandler.java
- src/main/java/org/example/coding_convention/common/exception/BaseException.java
- src/main/java/org/example/coding_convention/common/model/BaseResponseStatus.java
- src/main/java/org/example/coding_convention/common/model/BaseResponse.java
- src/main/java/org/example/coding_convention/file/model/FilesDto.java
The PhanesEditor project utilizes a centralized exception handling mechanism to ensure consistent API responses and robust error reporting across the system. This system intercepts exceptions thrown during request processing and transforms them into standardized JSON structures, preventing internal stack traces from leaking to the client while providing meaningful status codes and messages.
The core of this architecture relies on a Spring @RestControllerAdvice that captures specific exception types and maps them to a uniform BaseResponse object, utilizing a pre-defined enumeration of status codes and messages.
Exception Architecture
The architecture consists of a hierarchy starting from a custom runtime exception, managed through an advice class, and returned via a common response model.
Centralized Exception Handler
The GlobalExceptionHandler class acts as the central interceptor for all controllers. It uses the @ExceptionHandler annotation to define logic for specific exception classes.
The diagram shows the flow of an exception from the moment it is thrown in the business logic until it is returned as a standardized response.
Sources: GlobalExceptionHandler.java:18-20, BaseResponse.java:12-15
Core Components
| Component | Description |
|---|---|
BaseException | A custom RuntimeException that holds a BaseResponseStatus object. |
GlobalExceptionHandler | Intercepts exceptions and converts them into ResponseEntity objects. |
BaseResponseStatus | An enum defining success/error flags, internal codes, and human-readable messages. |
BaseResponse | The generic wrapper for all API responses, including errors. |
Sources: BaseException.java:7-10, GlobalExceptionHandler.java:16, BaseResponseStatus.java:9, BaseResponse.java:10
Exception Mapping and Logic
The system distinguishes between validation errors and business logic exceptions, applying different handling strategies for each.
Custom Business Exceptions
The BaseException class allows developers to throw errors with specific internal status codes. These are caught by the handler, which then determines the appropriate HTTP status code based on the internal code range.
The sequence diagram illustrates how the GlobalExceptionHandler determines the HTTP status code based on the internal range of the BaseResponseStatus.
Sources: GlobalExceptionHandler.java:21-28, GlobalExceptionHandler.java:46-52
Validation Error Handling
When @Valid or @Validated constraints fail, a MethodArgumentNotValidException is triggered. The handler iterates through all field errors to provide a detailed map of validation failures.
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity handleException(MethodArgumentNotValidException e) {
Map<String, String> errors = new HashMap<>();
for(FieldError error : e.getBindingResult().getFieldErrors()) {
errors.put(error.getField(), error.getDefaultMessage());
}
log.error(errors.toString());
return ResponseEntity.status(400).body(BaseResponse.error(REQUEST_ERROR, errors));
}
Sources: GlobalExceptionHandler.java:32-41
Response Status Codes
The project uses a structured numbering system for BaseResponseStatus to categorize different error types.
| Range | Category | Example Messages |
|---|---|---|
| 20000 | Success / JWT Errors | "요청에 성공하였습니다.", "JWT 토큰이 만료되었습니다." |
| 30000 | Request / Validation | "입력값을 확인해주세요." |
| 40000 | Response / DB Row | "값을 불러오는데 실패하였습니다.", "DB의 유효한 ROW가 존재하지 않습니다." |
| 50000 | Database | "데이터베이스 연결에 실패하였습니다." |
| 60000 | Server | "서버와의 연결에 실패하였습니다." |
Sources: BaseResponseStatus.java:19-75
Manual Validation and Throwing Exceptions
In cases where standard annotations are insufficient, manual validation is performed within DTOs or services, throwing IllegalArgumentException which is currently managed within the broader Spring context or converted to BaseException.
For example, in FilesDto.ContentUpdateReq, manual validation is implemented:
public void validate() {
if (fileName == null || fileName.isBlank()) {
throw new IllegalArgumentException("fileName 은 필수입니다.");
}
if (projectId == null) {
throw new IllegalArgumentException("projectId 는 필수입니다.");
}
}
Sources: FilesDto.java:18-29
Conclusion
The Global Exception Handling system in PhanesEditor-BE provides a structured and predictable error management framework. By separating internal business status codes from HTTP status codes, and centralizing the transformation logic in GlobalExceptionHandler, the project maintains a clean separation of concerns while ensuring that the frontend receives consistent error metadata across all API endpoints.