[Java] Exception을 Custom하여 사용해보자

chiyongs·2022년 6월 27일
5
post-thumbnail

프로젝트를 진행하면서 나타나는 대부분의 예외들은 Java에서 지원해주는 Exception으로 처리할 수 있고 무슨 예외인지 파악할 수 있습니다.

Custom한 Exception을 사용하는 이유는 무엇일까요?

  • 상세한 예외 정보를 제공할 수 있습니다.
  • Enum과 함께 사용하여 예외에 대한 응집도를 높일 수 있습니다.
  • @ControllerAdvice, @RestControllerAdvice에서 해당 Custom Exception에 대한 자세한 후처리가 가능합니다.

상세한 예외 정보 제공

우리는 Java에서 지원해주는 Exception으로도 어느정도 해당 Exception에 대한 정보를 제공할 수 있습니다.

new NoSuchElementException("존재하지 않는 상품입니다.")

하지만, 때때로 에러와 관련된 더 자세한 내용을 전달해야 할 경우가 존재합니다. 해당 에러로 인해 특정 HttpStatus를 응답으로 보내주어야 하는 경우를 예로 들 수 있습니다.

@Getter
public class CustomException extends RuntimeException {
	private HttpStatus httpStatus;
    private String message;

    public CustomException(HttpStatus httpStatus, String message) {
		this.httpStatus = httpStatus;
        this.message = message;
    }
}

이렇게 CustomException을 제작한다면 해당 에러와 관련된 메세지에 추가로 HttpStatus 또한 전달할 수 있게 됩니다.

Enum과 함께 사용해보자

Java의 Enum은 여러 장점을 가지고 있습니다.

  • 문자열과 비교해 IDE의 자동완성, 오타검증 등 적극적인 지원을 받을 수 있습니다.
  • 리팩토링 시 변경 범위가 최소화됩니다.
  • 상태와 행위를 한 곳에서 관리할 수 있습니다.
  • 명시적으로 해당 값이 무엇을 의미하는 지 알기 쉽습니다. 등등...

이런 장점을 가지고 있는 Enum을 사용하여 에러 코드들을 한 곳에서 관리해보겠습니다.

@Getter
@RequiredArgsConstructor
public enum ErrorCode {

    //== 200 ==//
    SUCCESS(HttpStatus.OK, "OK"),

    //== 400 ==//
    NOT_SUPPORTED_HTTP_METHOD(HttpStatus.BAD_REQUEST,"지원하지 않는 Http Method 방식입니다."),
    NOT_VALID_METHOD_ARGUMENT(HttpStatus.BAD_REQUEST,"유효하지 않은 Request Body 혹은 Argument입니다."),
    USER_NOT_FOUND(HttpStatus.BAD_REQUEST, "해당 사용자를 찾을 수 없습니다."),
    ITEM_NOT_FOUND(HttpStatus.BAD_REQUEST, "해당 상품을 찾을 수 없습니다."),

    private final HttpStatus status;
    private final String message;

}

이제 ErrorCodeCustomException에 적용해보겠습니다.

@Getter
public class CustomException extends RuntimeException {
    private ErrorCode errorCode;

    public CustomException(ErrorCode errorCode) {
        this.errorCode = errorCode;
    }
}

ErrorCodeHttpStatus와 전달할 메세지(String)를 가지고 있기 때문에 CustomException의 기존 필드를 완전히 대체하였습니다. 또한, ErrorCode로 에러들에 대한 추가, 수정, 삭제가 한 곳에서 이루어지기 때문에 변경의 범위가 최소화되는 것을 알 수 있습니다.

자세한 후처리

이제 CustomException을 통해 에러에 관련된 내용을 전달하는 Custom한 Response를 만들어보겠습니다.

@Getter
@Builder
@RequiredArgsConstructor
public class ErrorResponse {
    private final HttpStatus status;
    private final String code;
    private final String message;

    public ErrorResponse(ErrorCode errorCode) {
        this.status = errorCode.getStatus();
        this.code = errorCode.name();
        this.message = errorCode.getMessage();
    }

    public static ResponseEntity<ErrorResponse> error(CustomException e) {
        return ResponseEntity
                .status(e.getErrorCode().getStatus())
                .body(ErrorResponse.builder()
                        .status(e.getErrorCode().getStatus())
                        .code(e.getErrorCode().name())
                        .message(e.getErrorCode().getMessage())
                        .build());
    }
}

이제 만든 ErrorResponse@RestControllerAdvice를 사용해봅시다.

@Slf4j
@RestControllerAdvice
public class ApiExceptionHandler {

    @ExceptionHandler(value = CustomException.class)
    public ResponseEntity<ErrorResponse> handleCustomException(CustomException e) {
    	// 에러에 대한 후처리를 할 수 있습니다. 본 예시에서는 로깅만 진행하였습니다.
        log.error("[handleCustomException] {} : {}",e.getErrorCode().name(), e.getErrorCode().getMessage());
        return ErrorResponse.error(e);
    }
}

이렇게 CustomException을 만들어 상세한 예외 정보를 제공해보고, Enum과 함께 예외에 대한 응집도도 높여보았으며, @RestControllerAdvice와 함께 자세한 후처리도 진행해봤습니다.


마무리

물론, Java에서 제공해주는 기본 Exception들로 굉장히 많은 에러들을 처리할 수 있습니다. 하지만, 저는 HttpStatus를 비롯해 예외에 대한 더 자세한 정보를 제공할 수 있고, Enum과 함께 사용하여 에러들을 한 곳에서 상태 관리를 할 수 있다는 장점으로 CustomException을 만들어 사용하고 있습니다. Custom한 Exception을 사용하셨던 분들 중에 Enum으로 에러 코드들을 관리하지 않고 여러 개를 생성해보셨던 분들도 본 예시를 보면서 활용해보시면 좋을 것 같습니다. 긴 글 읽어주셔서 감사합니다 😊

1개의 댓글

comment-user-thumbnail
2023년 12월 13일

이거 따라해서 한번에 했습니다. 감사합니다,.

답글 달기