Mytly 02: Request Body를 enum에 바로 바인딩할 때 예외 처리

Ho Saint·2023년 5월 3일
0

문제

Request Body에서 Enum을 바로 바인딩할 때 잘못된 Enum Constant의 이름을 입력할 경우 위와 같은 에러메시지를 보게 된다.

이 때 던져지는 예외는 HttpMessageNotReadableException인데 내가 원하는 메시지를 파싱하기가 쉽지 않고, 이미 정의해둔 MethodArgumentNotValidException 응답 스펙을 사용하고 싶었다.

과정

Bean Validation은 이미 바인딩된 객체에 대해서 유효성 검증을 수행하는데, 위와 같은 예외는 역직렬화 과정에서 입력받은 String을 name으로 갖는 enum constant를 찾지 못하여 Bean Validation이 수행되기 전 단계에서 일어난다.

처음 든 생각은 역직렬화에 사용되는 JsonCreator 메소드를 정의하여 메소드 내에서 유효성 검증을 수행하는 것이다.

  1. 메소드에서 MethodArgumentNotValidException을 직접 던지기

생성자 파라미터인 MethodParameter 클래스와 BindingResult 클래스에 대해 이해가 부족하기도 했고 예외를 직접 던지려다 보니 코드가 매우 지저분해진다는 생각이 들었다.

  1. Cutom Validator를 정의 후 메소드 파라미터에 적용

Custom Validator가 수행되지 않고 바로 메소드가 실행된다. 역시 Bean Validation 스펙과 @Validated 어노테이션에 대한 나의 이해가 부족한 것 같았다.

해결

  1. enum 대신 String에 바인딩한다.

다음과 같은 두가지 아쉬움이 있었다.

1-1. 입력받은 문자열부터 다시 enum constant를 얻는 추가 코드가 필요하다.

1-2. 입력받은 문자열을 검증할 때와 문자열로부터 enum constant를 얻을 때 O(N)의 작업이 두번 수행된다.
-> Enum Class 내부에 static 멤버로 name과 Enum Constant를 key, value로 갖는 HashMap을 정의하고 JsonCreator와 valueOf 메소드를 오버라이딩하는 식으로 개선할 수 있을 것 같다.

  1. JsonCreator에서 입력받은 문자열에 해당하는 Enum Constant가 없으면 null을 리턴하게 하고 @NotNull 어노테이션을 사용한다.

2-1. 만료 옵션을 선택하지 않았을 때 expirationPeriod을 null로 받으려 했었는데 이 경우에는 불가능하다.
2-2. @NotNull 어노테이션 이름만 봐서는 어떤 유효성 검증을 수행하는지 정확히 파악하기가 불가능하다.

두번째 방법을 선택했다.

추가

두가지 방법 다 완벽히 만족스럽지가 않아서 MethodArgumentException과 Bean Validation 그리고 Spring의 데이터 바인딩에 더 공부해보고 코드를 개선

profile
열정보다 시스템. 실수를 막을 수 있는 프로세스.

0개의 댓글