Back to posts

Bean Validation 과 jetbrains annotations

Bean Validation과 정적 분석용 null 어노테이션의 차이를 정리.


Bean Validation?

Jakarta Bean Validation은 표준 명세다. Hibernate Validator는 구현체다. (reference implementation이라고 봐도 된다)

대표적으로 @NotNull 같은 어노테이션이 있다. Spring Web을 쓰면 익숙하다. @Valid를 붙이면 자동으로 검사가 동작한다. 객체 그래프를 타며 복잡한 객체도 검사할 수 있다.

Spring이 없어도 Validator 인터페이스로 검사할 수 있도록 구현돼 있다. Spring은 DTO 바인딩 과정에서 검사를 수행하고, 문제가 있으면 MethodArgumentNotValidException을 던지도록 잘 추상화해 둔 것이다.

@Email, @CreditCardNumber 같은 어노테이션도 존재한다. 이미 생성된 객체의 포맷이나 유효성 검증에 적합하다.

다른 null 어노테이션들

Bean Validation에도 @NotNull이 있다. 그래서 다른 도구의 어노테이션과 헷갈리기 쉽다.

예를 들어:

  1. JetBrains @NotNull
  2. Lombok @NonNull
  3. JSpecify @Nullable, @NonNull, @NullMarked, @NullUnmarked

이 도구들은 정적 분석과 null 안정성 체크에 더 가깝다. 예를 들어 void setName(@NotNull String name)에 setName(null)을 넣으면 IDEA가 경고를 띄운다.

IntelliJ IDEA recognizes popular Java annotations and takes them into account when analyzing code https://www.jetbrains.com/help/idea/annotating-source-code.html#contract-annotations

Lombok은 바이트코드 조작으로 null 입력 시 예외를 추가해 주기도 한다.

종합

검사 시점, 바이트코드 조작 여부, IDEA 정적 분석 기준으로 나눌 수 있겠다.

Bean Validation은 정적 분석을 지원하지 않는다. 런타임에 Validator로 포맷과 유효성을 검사하는 도구다. 특징은 객체가 이미 생성된 후 검사가 이뤄진다는 점이다. 사전/사후/불변식 용도로 쓰기엔 적합해 보이지 않는다.

반면 나머지는 컴파일 시점 예외 로직을 추가하거나, IDEA에서 힌트를 주는 정적 도구에 가깝다. 객체 생성과 무관하게 인라인 검사를 담당한다.

둘 다 사전/사후/불변식 용도로 쓰기엔 아쉬움이 있다. 일단은 런타임 검사기인지, 컴파일타임 검사기인지로 구분해서 쓰는 게 좋겠다. JSpecify는 좀 더 주목할 만하다.