💻문제점
다음과 같이 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 |