Custom Validation
>Custom Validation
: 사용하는 Bean Validation에 내장된 애너테이션 중 나의 목적에 맞는 것이 없을때, 직접 애너테이션을 만들어 사용할 수 있다.
: 사용자 정의 유효성 검증을 하기 위해서는 Custom Annotaion과 이를 처리할 Custom Validator 클래스가 필요하다.
: Custom Annotation은 Custom Validator를 작동하게 만드는 스위치 역할을 하고, Custom Validator가 어떤 기능의 유효성 검증을 하는지에 대한 로직을 구현한다.
>Custom Annotaion
<코드 추가>
@interface
: 어노테이션은 인터페이스 중 특별한 종류의 인터페이스이므로 @interface 타입으로 선언하여 작성한다.
: @interface 뒤에는 어노테이션 이름을 작성한다.
: 커스텀 애너테이션에 아래의 애너테이션을 붙여 만듬으로써 다양한 기능을 구성한다.(메타 애너테이션)
@Target
: 어노테이션을 적용할 위치 선택
-Attribute
: 속성의 value 값으로 지정가능하다.
: 단독으로 쓰일 경우, value는 생략도 가능하다.
ElementType.PACKAGE : 패키지 선언
ElementType.TYPE : 타입 선언, 클래스, 인터페이스, Enum에 부착 가능
ElementType.ANNOTATION_TYPE : 어노테이션 타입 선언
ElementType.CONSTRUCTOR : 생성자 선언
ElementType.FIELD : 멤버 변수 선언
ElementType.LOCAL_VARIABLE : 지역 변수 선언
ElementType.METHOD : 메서드 선언
ElementType.PARAMETER : 전달인자 선언
ElementType.TYPE_PARAMETER : 전달인자 타입 선언
ElementType.TYPE_USE : 타입 선언
@Retention
: 어노테이션이 언제까지 유효한지를 나타냄
-RetentionPolicy.SOURCE : 컴파일 전까지만 유효
-RetentionPolicy.CLASS : 컴파일러가 클래스를 참조할 때까지 유효
-RetentionPolicy.RUNTIME : 컴파일 이후 런타임 시기에 JVM에 의해 참조가 가능(리플렉션)
@Constraint
@Constraint
:Custom Validator와 연결하는 애너테이션
: 속성값으로 (validateBy = CustomValidatorName.class)를 제공하여 연결한다.
//기타 정보 애너테이션
@Documented : 해당 어노테이션을 Javadoc에 포함시킴
@Inherited : 어노테이션의 상속을 가능하게 함
@Repeatable : Java8 부터 지원하며, 연속적으로 어노테이션을 선언할 수 있게 함
>Custom Validator
<코드 추가>
: 애너테이션은 추가 정보를 제공해주는 메타데이터이일 뿐이므로, 이를 해결하는 기능을 가진 객체가 필요하고 그게 Custom Validator이다.
: Custom Validator를 만들기 위해서는 반드시 ConstraintValidator를 구현해야한다.
: ConstraintValidator의 < > 내에는 첫번째 인자로 현재 작성하는 Custom Validator와 연결된 Custom Annotation을 넣고, 두번째 인자로는 Custom Anootation으로 검증할 대상의 타입을 작성한다.
>Custom 예시
Custom Annotation
Not Space : 애너테이션이 붙은 문자열이 공백이거나, 문자 사이 공백이 1개를 초과할 경우 유효성 검증에 걸림.
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
//메타 데이터를 제공하는 부분
@Target(ElementType.FIELD)
//정보1: 해당 애너테이션은 Field 에 붙일 수 있다.
@Retention(RetentionPolicy.RUNTIME)
//정보2: 해당 애너테이션은 RUNTIME 중에 JVM에 의해 작동된다.
@Constraint(validatedBy = {NotSpaceValidator.class})
//정보3: 해당 애너테이션은 NotSpaceValidator.class 와 연결되어 기능을 구현한다.
public @interface NotSpace { //@interface : 애너테이션은 특별한 인터페이스로 볼 수 있다. 이를 표시한 것이다.
//message(), groups(), payload()는 필수적으로 들어가야한다.
String message() default "공백이 아니어야 합니다.";
//유효성 검증 실패시 기본값으로 출력하는 메세지이다.
Class<?>[] groups() default {};
//유효성 검증을 할 group 을 지정하는 값
Class<? extends Payload>[] payload() default {};
//사용자가 추가 정보(payload)를 제공하는 값
}
Custom Validator
NotSpaceValidator
import org.springframework.util.StringUtils;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
//Custom Validator 를 만들기 위해서는 반드시 ConstraintValidator 를 구현해야 한다.
//ConstraintValidator<(1),(2)>
//(1) : Custom Validator 를 사용할 애너테이션
//(2) : (1)으로 검증할 대상의 타입
public class NotSpaceValidator implements ConstraintValidator<NotSpace, String> {
//initialize() : isValid 를 호출하기 위해서 validator 를 초기화하는 메서드이다.
//애너테이션이 부착된 곳의 정보를 가져와서 초기화한다.(정확하게 이해 못했다.)
@Override
public void initialize (NotSpace constraintValidator){
ConstraintValidator.super.initialize(constraintValidator);
}
//isValid() : 유효성 검증의 로직을 담은 메서드
//value 가 null 이거나, StringUtils.hasText(value)가 true 일 때, true 반환
//StringUtils.hasText(value) : value 가 null 이 아니고, 길이가 0보다 크고, 문자 사이 공백이 최대 1개이면 true 반환
@Override
public boolean isValid (String value, ConstraintValidatorContext context){
return value == null || StringUtils.hasText(value);
}
}