Spring MVC로 개발을 하다 보면, 컨트롤러에서 @Validated나 @valid를 사용해 객체를 검증한다. 그런데 문득 이런 의문이 생긴다.
"타입이 안 맞아서 바인딩이 실패하면, 왜 뒤에 붙여놓은
@Min이나@NotBlank같은 검증은 실행되지 않을까?"
김영한 강사님의 강의에서도 "타입 변환에 성공해서 바인딩에 성공한 필드여야 Bean Validation 적용이 의미가 있다"는 설명이 나온다. 왜 그런지 기술적, 논리적 이유를 정리해 보았다.
Spring은 HTTP 요청 파라미터를 처리할 때 엄격한 단계(Phase)를 거친다.
@NotNull, @Max 등)을 검사한다.여기서 핵심은 "바인딩 실패 시 해당 필드는 값이 없다"는 점이다.
만약 Integer age 필드에 "abc"라는 문자열이 들어왔다고 가정해 보자. 타입 변환에 실패했기 때문에 age 필드에는 정상적으로 담기지 못한다(보통 null 혹은 초기값). 값이 없는데 "이 값이 10보다 큰가?"(@Min(10))를 묻는 검증 프로세스는 기술적으로 무의미하며, 제대로 된 결과를 낼 수 없다.
사용자가 나이 입력창에 "abc"를 입력했을 때, 시스템은 "숫자를 입력해주세요"라는 에러를 보여줘야 한다. 만약 바인딩 실패를 무시하고 검증을 강제한다면, 내부적으로 값이 null이라서 발생하는 @NotNull 오류까지 함께 발생하게 된다. 사용자는 "나는 입력을 했는데 왜 값이 없다고 하지?"라며 혼란을 느끼게 된다.
더 큰 오류(타입 불일치)가 먼저 발견되었으므로, 세부적인 규칙 검사는 뒤로 미루는 것이 논리적으로 타당하다.
BindingResult에 FieldError를 담는다.결국 바인딩에 실패한 필드가 Bean Validation을 수행하지 않는 이유는, "검사할 데이터가 제대로 준비되어야 검사도 할 수 있다"는 아주 단순하고 명확한 원리 때문이다.
데이터 자체가 오염되었거나 존재하지 않는 상태에서의 검증은 논리적 모순을 낳기 때문에, "바인딩 성공 후에만 검증이 의미가 있다"는 말은 스프링이 제공하는 합리적인 배려라고 이해할 수 있다.