본문 바로가기
Spring boot

EnumVaild Anotation

by Subi 2023. 8. 1.

개요

  • Enum 의 대한 Request를 받는 DTO를 개발하던 중, Enum 대한 DTO를 어떤 자료형으로 받는게 맞을지 생각을 하다가, Enum.Class 에 저장되지 않은 값이 들어왔을 때에는 어떻게 처리하면 좋을 지에 대해 의문이 들었다.
  • 그러하여 만든 것이 Enum 에 대한 Vaildation 검사를 수행하는 Anotation 이였다.
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = EnumValidator.class)
public @interface EnumValid {
    String message() default "올바른 값이 아닙니다.";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
    Class<? extends Enum<?>> enumClass();

}
  • 기본적인 Anotation의 코드의 내용은 이렇게 되어있다.
  • Vaildation이 성립되지 않을 시 출력되는 message에 값과 여러가지 클래스가 담기는 객체들로 이루어져 있다.
  • 중요한 부분은 Class<? extends Enum<?>> 이다.
    • Enum Class를 받는 부분인데 , 하나의 Enum 클래스에 종속되지 않고 여러가지 Enum.Class 에 사용하고 싶어 제네릭을 이용해 객체를 받을 수 있게 만들었다.

그리고 EnumVaild 를 구현한 구현체 Class 이다.

public class EnumValidator implements ConstraintValidator<EnumValid, String> {

    private Class<? extends Enum<?>> enumClass;

    private String message;

    @Override
    public void initialize(EnumValid constraintAnnotation) {
        this.enumClass = constraintAnnotation.enumClass();
    }

    @Override
    public boolean isValid(String value, ConstraintValidatorContext context) {
        String toEnumStr = "";
        if("".equals(value) || value == null || enumClass == null) {
            context.disableDefaultConstraintViolation();
            context.buildConstraintViolationWithTemplate("객체가 비어있습니다").addConstraintViolation();
            return false;
        }
        for (Enum<?> enumVal : enumClass.getEnumConstants()) {
            toEnumStr += enumVal.name()+", ";
            if (enumVal.name().equals(value)) {
                return true;
            }
        }
        toEnumStr = toEnumStr.substring(0,toEnumStr.length()-2);
        context.disableDefaultConstraintViolation();
        context.buildConstraintViolationWithTemplate("유효하지 않은 값입니다 (유효한 값 :" + toEnumStr + ")").addConstraintViolation();

        return false;
    }
}
  • 형태를 살펴보게 되면 ConstraintValidator 로 Vaildation을 수행하는 인터페이스를 상속받게 되어있는데, ConstraintValidator 는 <어노테이션, 자료형> 을 받게된다.
    • 그래서 ConstraintValidator<EnumValid, String> 을 상속받게 설정하여 준다.
  • enumClass 와 message를 Custom 가능할 수 있도록 인자로 받게된다.
  • 2개의 메서드를 수정할 수 있도록 Override 받게 된다.
    • initialize 는 EnumValid 에서 Value로 받은 EnumClass 를 현재 Class에서 선언한 enumClass로 주입 시켜 준다.
    • isValid 에선 유효성 검사에 대한 로직을 수행하게 되는데 매게변수로 EnumVaild를 선언해 준 DTO의 객체의 값을 value로 받게 되고, 유효성 검사에 대한 결과 정보를 담은 객체 ConstraintValidatorContext를 받게된다.
  1. EnumValid를 선언해준 DTO의 객체를 Null 에 대한 검사를 진행한다.
if("".equals(value) || value == null || enumClass == null) {
    context.disableDefaultConstraintViolation();
    context.buildConstraintViolationWithTemplate("객체가 비어있습니다").addConstraintViolation();
    return false;
}
  • 만약 null 일 경우 context에 대한 Message 값을disableDefaultConstraintViolation 메서드를 실행해 초기화 시켜준 다음 buildConstraintViolationWithTemplate 에 Message를 만들어주고 addConstraintViolation 로 주입 시켜준다.
  • 그리고 결과는 false 을 return 시켜준다. ( 유효성 검사 실패 )
  1. 선언한 Enum.Class 에 해당하는 값인지 검사를 진행한다.
String toEnumStr = "";
for (Enum<?> enumVal : enumClass.getEnumConstants()) {
      toEnumStr += enumVal.name()+", ";
      if (enumVal.name().equals(value)) {
          return true;
      }
  }
  • 주입 받은 enumClass 를 이용해 현재의 value 값이 Enum.Class 에 있는지 반복문을 통해 검사한다.
  • value 값이 enumClass 값과 일치하면 true 를 return 시켜준다. ( 유효성 검사 성공 )
  • toEnumStr 로 주입받은 enumClass 의 값을 message 출력을 위해 String으로 가지게 된다.
  1. 일치하는 값이 없으면 유효하지 않은 값으로 유효성 검사를 끝내게 된다.
context.disableDefaultConstraintViolation();
context.buildConstraintViolationWithTemplate("유효하지 않은 값입니다 (유효한 값 :" + toEnumStr + ")").addConstraintViolation();

return false;
  • 마찬가지로 message의 초기화를 위해 disableDefaultConstraintViolation 메서드를 실행 시켜 초기화를 진행 주 유효하지 않은 값이라는 message 에 Enum에 대한 Name값을 합친 String 값을 포함시켜 Exception Message를 context 객체에 주입 시켜준다.
  • 그리고 false 을 return 시켜준다. ( 유효성 검사 실패 )

사용하는 예시는

@EnumValid(enumClass = SendLocation.class)
private String sendLocation;
  • String 으로 Request를 받아주고 @EnumValid 를 선언해 준다음 enumClass 에 EnumClass 에 대한 주입을 해주면 완성된다.

'Spring boot' 카테고리의 다른 글

i18N 다국어 API 개발  (0) 2023.08.14
Request Test  (0) 2023.08.01
ResponseEntity Code Convention  (0) 2023.07.26
ResponseResult 개발 진행  (0) 2023.07.26
Spring Filter  (0) 2022.05.11

댓글