Retention
RetentionPolicy.SOURCE: 컴파일 전까지만 유효하며 컴파일 이후에는 사라짐RetentionPolicy.CLASS: 컴파일러가 클래스를 참조할 때까지 유효함RetentionPolicy.RUNTIME: Reflection을 사용하여 컴파일 이후에도 JVM에 의해 계속 참조가 가능함
ElementType.PACKAGE: 패키지 선언시
ElementType.TYPE: 타입 선언시
ElementType.CONSTRUCTOR: 생성자 선언시
ElementType.FIELD: 맴버 변수 선언시
ElementType.METHOD: 메소드 선언시
ElementType.ANNOTATION_TYPE: 어노테이션 타입 선언시
ElementType.LOCAL_VARIABLE: 지역 변수 선언시
ElementType.TYPE_PARAMETER: 매개 변수 타입 선언시


@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface PhoneNumber {...}
RetentionPolicy.RUNTIME 을 적용하였다ElementType.FIELD를 적용하였다@Target({ElementType.TYPE, ElementType.Field}) 와 같이 사용하면 된다.@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface PhoneNumber {
String name() default "010-0000-0000"
}
@PhoneNumber로 어노테이션을 붙여주고@Constraint 어노테이션을 활용하면 사용자가 원하는 Constraint와 Validation을 만들어 이를 적용할 수 있다@Constraint 를 활용한 어노테이션으로 만들어 검증하겠다!@Constraint(validatedBy = {PhoneNumberValidator.class})
@Target({ElementType.FIELD}) // 어디에 적용시킬 건지
@Retention(RetentionPolicy.RUNTIME) // 언제 실행시킬 건지
public @interface PhoneNumber {
String message() default " 핸드폰 번호 양식에 맞지 않습니다 ex) 000-0000-0000";
String regexp() default "^\\d{2,3}-\\d{3,4}-\\d{4}$";
Class<?>[] groups() default { };
Class<? extends Payload>[] payload() default { };
}

해석
- 제약 조건을 구현하는 ConstraintValidator 클래스입니다.
- 지정된 클래스는 지정된 ValidationTarget에 대한 고유한 대상 유형을 참조해야 합니다.
- 두 ConstraintValidator가 동일한 유형을 참조하는 경우 예외가 발생합니다.
- 메소드 또는 생성자의 매개변수 배열(교차 매개변수라고도 함)을 대상으로 하는 - ConstraintValidator는 최대 하나가 허용됩니다. 둘 이상이면 예외가 발생합니다.
- 반환:
- 제약 조건을 구현하는 ConstraintValidator 클래스 배열
public class PhoneNumberValidator implements ConstraintValidator<PhoneNumber, String> {
private String regexp;
@Override
public void initialize(PhoneNumber constraintAnnotation) {
this.regexp = constraintAnnotation.regexp();
}
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
// value : phoneNumber 이 들어옴
boolean result = Pattern.matches(regexp,value);
return result;
}
}
ConstraintValidator를 상속받는 PhoneNumberValidator를 만들자@Pattern(regexp = "^\\d{2,3}-\\d{3,4}-\\d{4}$")
@Constraint(validatedBy = {PhoneNumberValidator.class})의 매개변수에 우리가 어떤 클래스로 검증할건지 명시해주면 끝이다!@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
@JsonNaming(value = PropertyNamingStrategies.SnakeCaseStrategy.class)
public class UserRegisterRequest {
private String name;
private String nickName;
@NotBlank
@Size(min = 1, max = 12)
private String password;
@NotNull
@Min(1)
@Max(120)
private Integer age;
@Email
private String email;
@PhoneNumber
private String phoneNumber;
@FutureOrPresent // 현재 or 미래
private LocalDateTime registerAt;
@AssertTrue(message = "name or nickName 중 반듯이 1개가 존재해야 합니다") // 해당 리턴값이 true일 때 실행하는 어노테이션, 반듯이 is라는 메서드에 붙여줘야 한다
public boolean isNameCheck(){
if (Objects.nonNull(name) && !name.isBlank()){
return true;
}
if (Objects.nonNull(nickName) && !nickName.isBlank()){
return true;
}
return false;
}
}
{
"result_code" : "",
"result_message" : "",
"data" : {
"name" : "",
"nick_name" : "홍길동",
"password" : "qwer",
"age" : 20,
"email" : "hong@gmail.com",
"phone_number" : "010-11112222",
"register_at" : "2024-06-17T09:09:09"
} ,
"error" : {
"error_message" : [
]
}
}
