Spring Boot 3 프로젝트에서 데이터를 검증하는 데 있어 가장 많이 사용되는 어노테이션 중 세 가지가 있습니다. 바로 @NotNull, @NotEmpty, @NotBlank입니다. 이 어노테이션들은 모두 Jakarta Bean Validation(Jakarta Validation API)의 일부로, 클라이언트로부터 받은 데이터를 서버 측에서 검증할 때 강력한 도구로 활용됩니다. 하지만 이 세 가지 어노테이션은 이름이 비슷한 만큼 혼동하기 쉽고, 사용 목적과 적용 대상이 미묘하게 다릅니다.
이번 포스팅에서는 세 어노테이션의 개념, 적용 대상, 실무 예제, 오류 메시지, 주의사항까지 모두 정리하여 Spring Boot 개발자라면 누구나 쉽게 이해하고 사용할 수 있도록 설명드리겠습니다.
✅ 유효성 검사 어노테이션 요약
어노테이션 Null 허용 여부 빈 값 허용 여부 공백 허용 여부 적용 가능한 타입
@NotNull | ❌ 불가 | ⭕ 허용 | ⭕ 허용 | 모든 참조 타입 |
@NotEmpty | ❌ 불가 | ❌ 불가 | ⭕ 허용 | 문자열, 컬렉션, 배열 등 길이 있는 타입 |
@NotBlank | ❌ 불가 | ❌ 불가 | ❌ 불가 | 문자열(CharSequence) 타입 |
각 어노테이션이 검사하는 대상이 다르기 때문에 잘못 사용하면 유효성 검사가 제대로 이루어지지 않을 수 있습니다. 따라서 상황에 맞는 어노테이션을 선택하는 것이 중요합니다.
🧪 테스트 환경 및 샘플 클래스 구성
먼저 아래와 같은 컨트롤러와 DTO 클래스들을 통해 각 어노테이션의 작동 방식을 비교 실험해볼 수 있습니다.
import jakarta.validation.Valid;
import jakarta.validation.constraints.*;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
public class ValidAnnotationController {
@PostMapping("/valid/notnull")
public ValidObject checkNotNull(@Valid @RequestBody ValidObject object) {
return object;
}
@PostMapping("/valid/notempty")
public ValidObjectEmpty checkNotEmpty(@Valid @RequestBody ValidObjectEmpty object) {
return object;
}
@PostMapping("/valid/notblank")
public ValidObjectBlank checkNotBlank(@Valid @RequestBody ValidObjectBlank object) {
return object;
}
@Getter
@AllArgsConstructor
public static class ValidObject {
@NotNull(message = "String cannot be null")
private String string;
@NotNull(message = "Integer cannot be null")
private Integer integer;
@NotNull(message = "Object cannot be null")
private Object object;
@NotNull(message = "List cannot be null")
private List<String> list;
@NotNull(message = "CustomObject cannot be null")
private CustomObject customObject;
}
@Getter
@AllArgsConstructor
public static class ValidObjectEmpty {
@NotEmpty(message = "String cannot be empty")
private String string;
@NotEmpty(message = "List cannot be empty")
private List<String> list;
}
@Getter
@NoArgsConstructor
@AllArgsConstructor
public static class ValidObjectBlank {
@NotBlank(message = "String cannot be blank")
private String string;
}
@Getter
@AllArgsConstructor
public static class CustomObject {
private Integer number;
}
}
🟡 @NotNull - 단순히 Null 여부만 체크
@NotNull은 해당 필드가 null이 아니기만 하면 유효성 검사를 통과합니다. 따라서 빈 문자열이나 빈 리스트도 통과합니다.
✅ 예시
@NotNull(message = "Name must not be null")
private String name;
🔎 사용 대상
- 모든 참조 타입(Object, String, List, Map 등)
- 숫자 타입 (Integer, Long 등) 포함 가능
❗ 주의사항
- GET 요청 파라미터의 경우 ?name= 처럼 빈 값을 전달하면 null이 아닌 빈 문자열이기 때문에 유효성 검사를 통과할 수 있습니다.
- 특히 문자열, 리스트, 맵 등 길이를 가질 수 있는 타입은 null이 아니더라도 값이 없는 상태일 수 있습니다.
📌 실습 결과
{
"string": "",
"integer": 5,
"object": null,
"list": [],
"customObject": null
}
- string은 빈 문자열이라도 통과
- list는 비어있지만 통과
- object, customObject가 null이므로 유효성 검사 실패
🟠 @NotEmpty - null과 빈 값을 모두 차단
@NotEmpty는 단순히 null뿐 아니라, **길이가 0인 상태(빈 문자열, 빈 컬렉션)**도 유효성 검사를 실패로 처리합니다.
✅ 예시
@NotEmpty(message = "List must not be empty")
private List<String> tags;
🔎 사용 대상
- String, List, Set, Map, 배열 등 길이를 가질 수 있는 타입
- Object, Integer, Double 등 길이가 없는 타입에는 사용 불가
❗ 주의사항
- null이거나 "", []이면 모두 유효성 검사에 실패합니다.
- Object, Integer 같은 타입에 사용할 경우 No validator found 예외 발생
📌 실습 결과
{
"string": "",
"list": []
}
→ 둘 다 유효성 검사 실패 (""와 빈 리스트는 길이가 0)
🟢 @NotBlank - 공백 문자까지 체크
@NotBlank는 null, 빈 문자열(""), 공백 문자(" ") 모두를 거부합니다. 즉, 실제 내용이 존재하는 텍스트만 허용합니다.
✅ 예시
@NotBlank(message = "Comment must not be blank")
private String comment;
🔎 사용 대상
- 오직 문자열(CharSequence 하위 타입)만 가능
- 공백 제거 후 길이가 0인 경우 실패 처리
❗ 주의사항
- List, Map, Integer 등에 적용하면 No validator found 예외 발생
- 사용자 입력을 받는 텍스트 필드 검증에 가장 적합
📌 실습 결과
{
"string": " "
}
→ 유효성 검사 실패 (공백만 포함)
🚧 잘못된 사용 예시
다음은 각각의 어노테이션을 잘못 적용한 예시입니다. 이처럼 어노테이션마다 허용하는 타입이 다르므로 정확한 이해가 필수입니다.
❌ @NotEmpty on Integer
@NotEmpty
private Integer age;
→ 실행 시 HV000030 오류 발생
해결 방법: @NotNull로 변경
📚 정리: 언제 어떤 어노테이션을 사용할까?
사용 목적 추천 어노테이션
값이 null인지 여부만 체크할 때 | @NotNull |
컬렉션이나 문자열이 비어있는지 체크할 때 | @NotEmpty |
문자열이 공백 포함 여부까지 체크할 때 | @NotBlank |
✅ 실무 팁
- 사용자 입력 텍스트: @NotBlank 추천
- 리스트/맵 필수 입력값: @NotEmpty 추천
- DB 키나 ID: @NotNull 추천
💬 마무리
Spring Boot 3에서 유효성 검사는 API의 신뢰성과 안전성을 보장하는 중요한 과정입니다. @NotNull, @NotEmpty, @NotBlank는 각각의 목적에 맞게 올바르게 사용하면 불필요한 오류를 방지하고 사용자에게 친절한 메시지를 전달할 수 있습니다.
이 세 어노테이션은 단순한 문법 이상으로, 서비스의 품질을 좌우할 수 있는 요소입니다. 이번 포스팅을 통해 각 어노테이션의 역할을 명확히 이해하고, 실무에서 자신 있게 활용해보시기 바랍니다.
'IT' 카테고리의 다른 글
파이썬 리스트 출력 시 따옴표 없이 출력하는 5가지 실전 방법 총정리 (0) | 2025.05.09 |
---|---|
[Python 기초] 문자열 포매팅 완벽 가이드 - format 함수와 f-string 비교 활용법 (1) | 2025.05.09 |
[Spring Boot 3] @Pattern 정규표현식 검증 완벽 가이드 – 실전 예제로 배우는 유효성 검증 (0) | 2025.05.09 |
Spring Boot 3에서 예외 처리를 책임지는 @RestControllerAdvice와 @ExceptionHandler 완벽 가이드 (0) | 2025.05.09 |
[Spring Boot 3] @Valid 예외 처리 완전 정복: MethodArgumentNotValidException vs BindException (0) | 2025.05.09 |