@NotNull, @NotEmpty, @NotBlank 어노테이션은 Spring에서 유효성 검사할 때 많이 사용하는 어노테이션입니다.
세 어노테이션의 차이와 용도에 대해 정리해보았습니다.
준비
import java.util.List;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import jakarta.validation.Valid;
import lombok.AllArgsConstructor;
import lombok.Getter;
@RestController
public class ValidAnnotationController {
@GetMapping("/valid/notnull")
public ValidObject checkNotNull(@Valid ValidObject object) {
return object;
}
@PostMapping("/valid/notnull")
public ValidObject checkNotNullPost(@Valid @RequestBody ValidObject object) {
return object;
}
@GetMapping("/valid/notEmpty")
public ValidObject checkNotEmpty(@Valid ValidObject object) {
return object;
}
@PostMapping("/valid/notEmpty")
public ValidObject checkNotEmptyPost(@Valid @RequestBody ValidObject object) {
return object;
}
@GetMapping("/valid/notBlank")
public ValidObject checkNotBlank(@Valid ValidObject object) {
return object;
}
@PostMapping("/valid/notBlank")
public ValidObject checkNotBlankPost(@Valid @RequestBody ValidObject object) {
return object;
}
@Getter
@AllArgsConstructor
public static class ValidObject {
private String string;
private Integer integer;
private Object object;
private List<String> list;
private CustomObject customObject;
}
@Getter
@AllArgsConstructor
public static class CustomObject {
private Integer number;
}
}
유효성 검사를 적용할 객체와 컨트롤러를 생성했습니다.
@NotNull
유효성 검사를 적용할 객체에 @NotNull 어노테이션을 붙여줍니다.
@Getter
@AllArgsConstructor
public static class ValidObject {
@NotNull(message = "String is Not Null")
private String string;
@NotNull(message = "Integer is Not Null")
private Integer integer;
@NotNull(message = "Object is Not Null")
private Object object;
@NotNull(message = "List is Not Null")
private List<String> list;
@NotNull(message = "CustomObject is Not Null")
private CustomObject customObject;
}
@Getter
@AllArgsConstructor
public static class CustomObject {
private Integer number;
}
먼저, 요청 값 없이 API를 실행해보겠습니다.
@NotNull 어노테이션이 붙어있기 때문에 값을 보내지 않고 요청을 실행하면 오류가 반환됩니다.
@NotNull 어노테이션은 값이 Null일 때 오류를 반환하기 때문에 Null로 들어온 변수의 개수만큼 에러카운트가 집계되었습니다.
주의사항
@NotNull을 GET Param 방식으로 사용했을 때 문제점이 있습니다.
Param에 변수만 넣고 값을 넣지 않았을 때 @NotNull 제약조건을 통과하는 경우가 있습니다.
key= 형식으로 사용하게 되면 빈 문자열이 들어가기 때문에 @NotNull 조건을 통과하게 됩니다.
하지만 Integer 타입은 빈 문자열을 숫자로 변환할 수가 없어서 @NotNull 제약 조건에 걸렸습니다.
정리하면, @NotNull은 값이 Null일 때만 검사를 합니다.
빈 문자열이든 무엇이든 값이 있기만 하면 검사를 통과할 수 있습니다.
@NotEmpty
@NotEmpty 어노테이션은 Null이나 빈 문자열 등 비어있는 상태를 체크합니다.
유효성 검사를 체크할 객체를 준비합니다.
@Getter
@AllArgsConstructor
public static class ValidObject {
@NotEmpty(message = "String is Not Empty")
private String string;
@NotEmpty(message = "List is Not Empty")
private List<String> list;
}
@Getter
@AllArgsConstructor
public static class CustomObject {
private Integer number;
}
이번에는 Integer 타입과 Object 타입, 사용자 정의 객체 타입을 제외했습니다.
그 이유는 @NotEmpty는 유효성 검사를 진행할 때 길이 값을 사용하는데, Integer같은 숫자 타입이나 Object 타입은 길이가 없어서 @NotEmpty를 사용할 수 없기 때문입니다.
@NotEmpty를 쓸 수 없는 타입에 사용하면 이런 오류가 발생합니다.
HV000030: No validator could be found for constraint 'jakarta.validation.constraints.NotEmpty' validating type 'java.lang.Object'. Check configuration for '<변수명>'
@NotEmpty 사용 가능 여부는 @NotEmpty 유효성 검사보다 먼저 진행되기 때문에 변수에 @NotEmpty를 사용할 수 있는지 없는지 여부를 먼저 확인해야 합니다.
값이 Null이거나 빈 문자열이거나 빈 컬렉션일 때 유효성 검사를 통과하지 못합니다.
빈 문자열이나 빈 컬렉션은 길이가 0이기 때문입니다.
정리하면, @NotEmpty는 null이 아니거나 길이가 0보다 커야 유효성 검사를 통과할 수 있습니다.
@NotBlank
@NotBlank를 사용하기 위한 객체입니다.
@Getter
@NoArgsConstructor
@AllArgsConstructor
public static class ValidObject {
@NotBlank(message = "String is Not Blank")
private String string;
}
이전과는 다르게 String 변수만 존재합니다.
그 이유는 @NotBlank는 문자열, 정확하게 말하면 CharSequence 타입에만 사용할 수 있기 때문입니다.
@NotBlank 역시 사용할 수 없는 타입에 사용하게되면 오류가 발생합니다.
HV000030: No validator could be found for constraint 'jakarta.validation.constraints.NotBlank' validating type 'java.util.List<java.lang.String>'. Check configuration for '<변수명>'
@NotBlank가 적용된 결과입니다.
@NotBlank는 이름 그대로 공백을 허용하지 않는다는 의미입니다.
그래서 길이가 0을 넘겨도 공백 문자만 있으면 유효성 검사를 통과하지 못합니다.
결론
3가지 어노테이션의 용도와 차이점을 정리하면,
@NotNull -> Null 여부만 체크합니다. 그래서 Null만 아니면 통과할 수 있습니다.
@NotEmpty -> Null 여부와 길이를 체크합니다. 그래서 길이를 체크할 수 있는 타입(String, Collection 등)만 사용 가능합니다.
@NotBlank -> Null 여부와 공백 여부를 체크합니다. 문자열 타입만 사용할 수 있습니다.