ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Spring] 유효성 검사에서 @Valid 와 setField 중 무엇이 먼저 실행될까
    📚 개발백과 2024. 8. 8. 14:41
    728x90
    public class RequestDto {
    	
        @Getter
        public static class BaseInfo {
    
            @Schema(description = "유저의 계좌 id", example = "123456789012")
            @NotNull(message = "계좌번호 입력은 필수입니다.")
            @TrimmedSize(value = 12, message = "계좌번호는 12자리이어야 합니다.")
            private String accountId;
    
            private void setAccountId(String accountId){
                this.accountId = (accountId != null) ? accountId.trim() : null;
            }
        }
    }

     

    다음과 같은 코드에서,

    1) custom valid Annotation인 @TrimmedSize

    2) setAccountId 의 trim()

     

    둘 중 무엇이 먼저 호출되는지 궁금해졌다.

     

     

    어노테이션의 내부로직과 setter(편의상 이렇게 부르겠음) 모두 "  123456789012  " 가 파라미터로 들어오면 "123456789012" 로 변환해주는 기능이다.

     

    @TrimmedSize 어노테이션 구현 코드

    더보기

    TrimmedSize. java

    @Constraint(validatedBy = TrimmedSizeValidator.class)
    @Target({ ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.PARAMETER })
    @Retention(RetentionPolicy.RUNTIME)
    public @interface TrimmedSize {
        String message() default "필드는 반드시 {value} 길이를 넘기면 안됩니다.";
        Class<?>[] groups() default {};
        Class<? extends Payload>[] payload() default {};
        int value();
    }

     

     

    TrimmedSizeValidator.java

    public class TrimmedSizeValidator implements ConstraintValidator<TrimmedSize, String> {
    
        private int size;
    
        @Override
        public void initialize(TrimmedSize constraintAnnotation) {
            this.size = constraintAnnotation.value();
        }
    
        @Override
        public boolean isValid(String value, ConstraintValidatorContext constraintValidatorContext) {
            if (value == null){
                return false;
            }
            return value.trim().length() == size;
        }
    }

     


    순서

    setAccountId  -->  유효성 검사

     

    1. 객체 생성 및 초기화

     

    RequestDto.BaseInfo 객체가 생성되고 필드가 초기화된다.

     

    accountId 필드에 JSON 본문에서 받은 값이 할당되는 과정에서 setAccountId 메서드가 호출되어 trim() 처리가 수행된다.

     

     

    2. 유효성 검사

     

    그 다음에 스프링이 유효성 검사를 수행한다.

     

    이 시점에서 @Valid 어노테이션이 적용된 객체에 대해 유효성 검사를 진행하므로 @TrimmedSize 어노테이션이 있는 필드가 검사된다..

     

    이때 setAccountId 메서드에서 trim 처리가 이미 되어 있으므로, 유효성 검사에는 trim 된 값이 사용된다.

     


    어노테이션의 내부로직과 setter 모두 trim() 처리를 하니까 하나만 사용하면 된......다 라고 하기에는 잠시,

     

     

    @TrimmedSize 만 사용할 경우

    유효성 검사에서는 trim() 처리를 해주는 것이 맞다.

    하지만! 유효성 검사에서만 전처리하는거지, 서비스 레이어로 넘어갈 때는 trim 처리가 되어있지 않은 기존 스트링이 그대로 넘어간다.

     

     

    나의 경우,

    전처리해서 유효성 검사를 하고 서비스레이어에도 trim처리된 값을 보내고 싶었다.

    그렇다면 setAccountId 내에서 trim() 을 수행해야한다.

    또한, 이렇게 된다면 @TrimmedSize 를 굳이 구현할 필요도x.. @Size 로 길이 검사만 해주면 된다.

     


     

     

     

     

    728x90
Designed by Tistory.