ABOUT ME

-

오늘 방문자
-
어제 방문자
-
전체
-
  • Enum 유효성 검사하기
    Spring 2021. 8. 23. 22:58
    요약
    - @Pattern과 enum은 같이 쓸 수 없다.
    - 커스텀어노테이션을 만들어서 @JsonCreator와 같이 사용해서 처리했다.

     

    파라미터 검증중 @Valid + @Pattern 이용해서 enum을 검증하려고 했다. 

    예를들어 Y,N만 들어가는 enum 타입의 멤버필드에  A를 집어 넣으려고한다면???

     

    물론 데이터가 들어가진 않겠지만 에러코드가 상당히 이쁘지 않을 것이다.

     

    아래 코드를 통해 처리했다.

     

    DTO

    import com.example.test.test.constant.YnCode;
    import javax.validation.constraints.Pattern;
    import lombok.Getter;
    import lombok.ToString;
    
    @Getter
    @ToString
    public class EnumRequestDto {
    
        private String name ;
    
        @Pattern(regexp = "Y|N") // 작동할까?
        private YnCode ynCode;
    
    }

    enum

    public enum YnCode {
        Y("Y"),
        N("N"),
        ;
    
        private final String code;
    
        YnCode(String code) {
            this.code = code;
        }
    
        public String getCode() {
            return code;
        }
     }

    controller

    @PostMapping("/yncode")
        public String insertYnCode(@RequestBody @Valid EnumRequestDto enumRequestDto) {
            log.info("insertYnCode param : {}", enumRequestDto);
            return "OK";
        }

    test

     

    json parse error! 발생

    Resolved [org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot deserialize value of type `com.example.test.test.constant.YnCode` from String "ABC": not one of the values accepted for Enum class: [NONE, Y, N]; nested exception is com.fasterxml.jackson.databind.exc.InvalidFormatException: Cannot deserialize value of type `com.example.test.test.constant.YnCode` from String "ABC": not one of the values accepted for Enum class: [Y, N]

     

     

    enum을 검증하려면 커스텀어노테이션을 만들어야 한다...

     

    커스텀 어노테이션 만들기

    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    import javax.validation.Constraint;
    import javax.validation.Payload;
    
    @Constraint(validatedBy = EnumPatternValidator.class)
    @Target({ElementType.FIELD})
    @Retention(RetentionPolicy.RUNTIME)
    public @interface EnumPattern {
        String regexp();
        String message() default "does not match \"{regexp}\"";
        Class<?>[] groups() default {};
        Class<? extends Payload>[] payload() default {};
    }
    import java.util.regex.Matcher;
    import java.util.regex.Pattern;
    import java.util.regex.PatternSyntaxException;
    import javax.validation.ConstraintValidator;
    import javax.validation.ConstraintValidatorContext;
    
    public class EnumPatternValidator implements ConstraintValidator<EnumPattern, Enum<?>> {
        private Pattern pattern;
    
        @Override
        public void initialize(EnumPattern annotation) {
            try {
                pattern = Pattern.compile(annotation.regexp());
            } catch (PatternSyntaxException e) {
                throw new IllegalArgumentException("pattern regex is invalid", e);
            }
        }
    
        @Override
        public boolean isValid(Enum<?> value, ConstraintValidatorContext context) {
            if (value == null) {
                return false;
            }
    
            Matcher m = pattern.matcher(value.name());
            return m.matches();
        }
    }

     

    자이제 적용해 보자.

     @EnumPattern(regexp = "Y|N", message = "Y 또는 N만 입력 가능합니다")
     private YnCode ynCode;

     

    띠롱. JSON parse error 발생..

     

    왜냐하면 애당초 enum에 정해진 값외 들어와 버리면 JSON parse error가 난다.

    그럼 어떻게 해야할까?

     

    @JsonCreator를 이용했다.

    이걸 사용하면 하면 JSON 객체를 deserialize해서 객체맵핑시 사용할 생성자를 지정할 수 있게 해준다.

    파라미터로 Y,N값이외의 값이 들어오면 null을 전달하게하였다.

    그러면 EnumPatternValidator에 NONE이 전달되고 Pattern class를 통해서 일치여부를 검증한다.

    import com.fasterxml.jackson.annotation.JsonCreator;
    import java.util.stream.Stream;
    
    public enum YnCode {
        Y("Y"),
        N("N")
        ;
    
        private final String code;
    
        YnCode(String code) {
            this.code = code;
        }
    
        public String getCode() {
            return code;
        }
    
        @JsonCreator(mode = JsonCreator.Mode.DELEGATING)
        public static YnCode findByCode(String code) {
            return Stream.of(YnCode.values())
                .filter(c -> c.code.equals(code))
                .findFirst()
                .orElse(null);
        }
    }

     

    아주 친근한 exeption이 발생했다. MethodArgumentNotValidException ^^

    이제 에러 메세지를 이쁘게 가공해서 내려주면 끝.

     

     

     

    참고로

    @JsonCreator와 @Pattern만 사용해도 작동하지 않을까? 생각이들었지만 enum + @Pattern은 작동하지 않는다.

    validation.UnexpectedTypeException 발생

     

    javax.validation.UnexpectedTypeException: HV000030: No validator could be found for constraint 'javax.validation.constraints.Pattern' validating type 'com.example.test.test.constant.YnCode'. Check configuration for 'ynCode'

     

     

     

    다른 방법이 있다면 공유부탁드리겠습니다^^ ㅎㅎ

    댓글

Designed by Tistory.