🚀 프로젝트/🥁 두둥

[Spring] 스프링 Enum Validator Reflection 으로 개선 및 구현하기

gengminy 2023. 2. 21. 14:05

https://gengminy.tistory.com/47

 

[Spring] 스프링에서 Enum 클래스 Validation 추가하기 (Enum JSON parse error 해결)

스프링에서 일반적으로 RequestBody 의 값을 Validation 하는 방법 스프링 MVC 에서 @Valid 어노테이션을 명시해주면 컨트롤러에서 해당 값에 대해 미리 Validation 해줘서 값이 들어오게 된다. JAVAX 에서 @Not

gengminy.tistory.com

 

앞서 작성한 스프링에서 Custom Enum Constraint Validator 구현하기

이 글에서 @Enum 이라는 커스텀 어노테이션을 만들었고

Request 필드에서 적용해보았다.

 

@Schema(defaultValue = "OPEN", description = "오픈 상태")
@Enum(target = EventStatus.class, message = "올바른 값을 입력해주세요.")
private EventStatus status;

하지만 이런식으로 작성하게 되면

매번 검증하고자 하는 Enum 클래스를 위처럼 명시해줘야 한다.

이게 보기 싫기 때문에 Reflection 을 통해 동적으로 Enum 클래스의 value 를 가져와 검증하려고 했다.

 

리플렉션(Reflection) : 실행 중인 프로그램의 클래스, 메서드, 필드 등의 정보를 동적으로 조사하고 사용하는 기능
클래스의 이름을 문자열로 받아와 그 클래스를 동적으로 로딩하거나, 인스턴스의 메소드나 필드를 호출하거나, 어떤 클래스가 어떤 인터페이스를 구현하고 있는지, 어떤 클래스가 어떤 클래스를 상속받았는지 등의 정보를 런타임에 조사할 수 있다.

 

📌 원하고자 하는 목표

@Schema(defaultValue = "OPEN", description = "오픈 상태")
@Enum(message = "올바른 값을 입력해주세요.")
private EventStatus status;

위 처럼 @Enum 사용 시 조사할 Enum 클래스를 생략하고 싶다.

 

📝 Enum

@Constraint(validatedBy = {EnumValidator.class})
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface Enum {
    String message() default "Invalid Enum Value.";

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};
}

target 필드를 제외하여 재정의한다.

 

 

📝 EnumValidator

public class EnumValidator implements ConstraintValidator<Enum, java.lang.Enum> {
    @Override
    public boolean isValid(java.lang.Enum value, ConstraintValidatorContext context) {
        if (value == null) {
            return false; //null 값 허용 여부
        }

        Class<?> reflectionEnumClass = value.getDeclaringClass();
        return Arrays.asList(reflectionEnumClass.getEnumConstants()).contains(value);
    }
}

여러 가지 방법을 찾아보았는데 위의 방법이 가장 효과적인 것 같아서 채용했다

 

우선 해당 Enum 값이 null 일 경우를 검사한다.

여기서는 null 에 해당하는 값은 검증에 실패하도록 정책을 설정했다.

 

이후 이 Enum 값이 null 이 아님이 보장되었기 때문에

value.getDeclaringClass 를 통해 이 value 가 속한 Enum 클래스 정보를 가져온다.

 

이제 Enum Class 를 알아냈으니 이 Enum 에 속해있는 Constant 들을 가져와 비교하면 된다.

비교는 Collection 의 contains 메소드를 이용하여 축약시켰다.

 

 

이제 target 을 지정하지 않아도

동적으로 Enum Class 정보를 가져와 Validation 할 수 있게 되었다!

 

올바르게 검증해주는 모습

 

 

🌎 구현 과정 관련 게시글

📎 Custom Enum Validator 구현하기

 https://gengminy.tistory.com/47

📎 Reflection 을 이용하여 Enum Validator 개선하기

https://gengminy.tistory.com/48

📎 Custom Enum Deserializer 구현하여 Enum 에 없는 값 null 로 파싱하기

https://gengminy.tistory.com/49