Clean Code that Works.

비밀번호 조합에서, 꼭 영문/숫자를 혼용하도록 해야 하는 요구사항이 있었다.
정규식으로 어찌저찌 해보고 @Pattern 을 사용해서 해볼려고 했지만.. 정규식으로는 안되는것 같았다.

하여, 그냥 만들어 보기로 결정.
JSR 303 구현체중 하나인 Hibernate Validator 를 사용 하는 중인데.
http://docs.jboss.org/hibernate/stable/validator/reference/en-US/html_single/#validator-customconstraints
여길 보면 자세히 설명이 되어 있다.

위 것을 참조 하여 일단 custom anontation을 만들어 보면, 아래와 같은 코드가 탄생..

@ConstraintComposition(CompositionType.AND)
@Target({ METHOD, FIELD})
@Retention(RUNTIME)
@Constraint(validatedBy = AlphabetAndNumberValidator.class)
public @interface AlphabetAndNumber {
     public abstract String message() default "{AlphabetAndNumber.message}";
     public abstract Class<?>[] groups() default { };
     public abstract Class<? extends Payload>[] payload() default { };
}

여기서 @Constraint 쪽에 제약 조건을 체크하는 클래스를 지정해 주어야 한다.

하여 AlphabetAndNumberValidator를 살펴 보면, 아래와 같은데.
isValid에서 제약 조건을 체크 하는 것을 볼 수 있다.
이 경우엔 영문을 가지고있는지, 숫자를 가지고 있는지 확인하고 이를 둘 다 가지고 있어야 통과 하도록.

public class AlphabetAndNumberValidator implements ConstraintValidator<AlphabetAndNumber, String> {

    @Override
    public void initialize(AlphabetAndNumber constraintAnnotation) {
    }
    @Override
    public boolean isValid(String value, ConstraintValidatorContext context) {
        if ( value == null) {
            return false;
        }
        Matcher matcher = Pattern.compile("[a-zA-Z]+").matcher(value);
        boolean isExistAlphabet = matcher.find();
        matcher = Pattern.compile("[0-9]+").matcher(value);
        boolean isExistNumber = matcher.find();
       
        if ( isExistAlphabet && isExistNumber) {
            return true;
        } else {
            return false;
        }
    }
}

이렇게 구현 한 후에 도메인 클래스나 기타 method 및 field에 @AlphabetAndNumber 를 붙여주고 valid 체크를 하게 되면 적용 된다.


아래 블로그에도 잘 정리 되어 있는데, 여기서 만든 custome validator는 Spring bean으로도 등록이 된다고 하니 다른 빈들을 참조 해서 좀 더 복잡한 제약 조건을 걸도록 만들수도 있다.
http://chanwook.tistory.com/855

하이버네이트 페이지에 설명이 상당히 잘 되어 있기 때문에, 아래 url 참고 해서 test 케이스 작성도 잊지 말도록 하자. :)
http://docs.jboss.org/hibernate/stable/validator/reference/en-US/html_single/#Using%20the%20constraint