Chef.Yeon
Code Cook
Chef.Yeon
전체 방문자
오늘
어제
  • 분류 전체보기 (230)
    • 게임 개발 (1)
      • Unity (1)
    • Android (27)
      • Kotlin (19)
      • 우아한테크코스 5기 (4)
    • Language (11)
      • 파이썬 (3)
      • Java (7)
    • DB (2)
      • SQL (16)
    • Spring (25)
    • 코딩테스트 (56)
    • Git (1)
    • TIL (85)
    • DevOps (6)

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

인기 글

태그

  • kibana
  • ec2
  • rsocket
  • 우아한테크코스
  • 내림차순
  • til
  • java
  • 프리코스
  • spring
  • kotlin
  • 코틀린 인 액션
  • 파이썬
  • grafana
  • 문자열
  • enum
  • 에라토스테네스의 체
  • 안드로이드
  • 코틀린
  • Docker
  • 프로그래머스
  • Wil
  • 다이나믹 프로그래밍
  • elasticsearch
  • webflux
  • 백준
  • SQL
  • MariaDB
  • 레포지토리
  • Android
  • 코딩테스트

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
Chef.Yeon

Code Cook

[TIL - 20230426] Enum 타입 필드 검증을 위한 커스텀 애노테이션 생성
TIL

[TIL - 20230426] Enum 타입 필드 검증을 위한 커스텀 애노테이션 생성

2023. 4. 26. 20:11

 

💻문제점

다음과 같이 job을 입력하지 않으면 에러가 발생한다. @Valid를 사용하려고 했지만, dto에서 job은 EnumType이므로 @NotBlank와 같은 애노테이션을 작성할 수 없었다.

public enum JobEnum {
    YOUTUBER("youtuber"),
    EDITOR("editor");

    private String job;

    JobEnum(String job) {
        this.job = job;
    }
}

📃시도

@NotNull 등 여러 애노테이션을 붙여봤지만, 전부 에러가 났다. 에러를 보니 애초에 @Valid 검증 단계로 넘어가기 전에, 문자열을 JSON으로 파싱하는 과정에서 오류가 발생했던 것이다.

Resolved [org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot coerce empty String ("") to `edit.edit.entity.JobEnum` value (but could if coercion was enabled using `CoercionConfig`)]

 payload의 job이 enumType인 JobEnum에 포함되지 않는 값이기 때문이다.


🔍해결

EnumClass를 작성할 때 JsonCreator 애노테이션을 작성해 파싱 메서드를 지정해 주었다.

JSON 파싱을 시도할 때 JobEnum에 없는 값이라면 null을, 제대로된 값을 가진다면 해당 value를 가질 것이다.

public enum JobEnum {
    YOUTUBER("youtuber"),
    EDITOR("editor");

    private String job;

    JobEnum(String job) {
        this.job = job;
    }

    public String getJob() {
        return job;
    }

    @JsonCreator(mode=JsonCreator.Mode.DELEGATING)
    public static JobEnum get(String code) {
        return Arrays.stream(JobEnum.values())
                .filter(type -> type.getJob().equals(code))
                .findAny()
                .orElse(null);
    }
}

 

검증을 위해 커스텀 EnumValid 애노테이션을 생성해주었다.

@Traget으로 적용대상을 지정하고, @Rentention을 통해 컴파일 이후 런타임에도 참조가 가능하도록 했다.

@Contraint를 통해 EnumValidator클래스를 통해 검증을 하도록 하였다.

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

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

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

이제, EnumType의 유효성 검증을 위해서 null인지 아닌지만 판단하면 된다.

public class EnumValidValidator implements ConstraintValidator<EnumValid, Enum<?>> {

    @Override
    public void initialize(EnumValid constraintAnnotation) {
        ConstraintValidator.super.initialize(constraintAnnotation);
    }

    @Override
    public boolean isValid(Enum<?> value, ConstraintValidatorContext context) {
        return value != null;
    }
}

 

message.properties에 enumvalid 메시지를 정의하여 사용했다.

@Getter
@Setter
@Builder
public class SignupRequestDto {

    @Size(min = 4, max = 10, message = "{userId.size}")
    @NotBlank
    @Pattern(regexp = "^[a-z0-9]*$", message = "{userId.pattern}")
    private String userId;

    @Size(min = 8, max = 15, message = "{password.size}")
    @NotBlank
    @Pattern(regexp = "(?=.*[0-9])(?=.*[a-zA-Z])(?=.*\\W)(?=\\S+$).{8,15}", message = "{password.pattern}")
    private String password;

    @Email
    @NotBlank
    private String email;

    @Size(min = 2, max = 10)
    @NotBlank
    private String nickname;
    
    @EnumValid(message = "{job.enumvalid}")
    private JobEnum job;

    public Member toEntity(String encodedPassword) {
        return Member.builder()
                .userId(userId)
                .password(encodedPassword)
                .email(email)
                .nickname(nickname)
                .job(job)
                .build();
    }
}

728x90

'TIL' 카테고리의 다른 글

[TIL - 20230428] failed to lazily initialize a collection of role  (0) 2023.04.28
[TIL - 20230427] message properties 사용한 @Valid 메시지 처리  (0) 2023.04.27
[TIL - 20230420] ControllerAdvice, ExceptionHandler 전역 예외 처리  (0) 2023.04.20
[TIL - 20230419] JWT  (0) 2023.04.19
[TIL - 20230418] JWT  (0) 2023.04.18
    'TIL' 카테고리의 다른 글
    • [TIL - 20230428] failed to lazily initialize a collection of role
    • [TIL - 20230427] message properties 사용한 @Valid 메시지 처리
    • [TIL - 20230420] ControllerAdvice, ExceptionHandler 전역 예외 처리
    • [TIL - 20230419] JWT
    Chef.Yeon
    Chef.Yeon
    보기 좋고 깔끔한 코드를 요리하기 위해 노력하고 있습니다.

    티스토리툴바