현재 개인 프로젝트를 진행중에 있어서 컨트롤러 클래스에서 요청을받는데, 요청을 받는 DTO 클래스에 BeanValidation 설정을 해놨다.
그런데 여기서 Bean Validation의 검증로직을 통과하지 못한 경우와, 통과가 되어서 정상처리 된 경우에 대해서 두가지 처리를 해야하는 분기가 생겼다.
Bean Validaiton의 검증을 통과하지 못한 경우 BindingResult의 정보를 반환하려고 해보니 직렬화 문제가 생겼다.
com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class org.springframework.validation.DefaultMessageCodesResolver and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: org.springframework.validation.BeanPropertyBindingResult["messageCodesResolver"])
BeanSerializer
여기서 발생한 문제가 BindingResult 객체를 반환하려고 할 때 해당 객체에 대한 Jackson 라이브러리의 직렬화할 수 없는 클래스(DefaultMessageCodesResolver
) 가 포함되어있어 Jackson이 직렬화 오류를 던진것.
알아보니 기본적으로 BindingResult는 Spring 내부에서 사용되는 객체여서 직렬화가 가능한 형태가 아니라고 한다.
그러니깐 응답 및 요청을 보낼 때에는 보통 @ResponseBody, @RequestBody가 이러한 직렬화 작업을 해주지만 현재 BindingResult는 그런 기능이 없다는것이다.
그래서 직렬화 가능한 형태가 아니여서(자바 객체가 -> JSON 형식으로 변형이 불가능한 상태) BindingResult의 에러 정보를 직접 추출하고 이를 커스텀해야한다.
@AllArgsConstructor
@Getter
public class ErrorResponseBindingResult {
private final String defaultMessage;
private final String errorField;
private final String rejectedValue;
private final String errorAnnotation;
public static List<ErrorResponseBindingResult> fromBindingResult(List<FieldError> errors) {
return errors.stream()
.map(fieldError -> new ErrorResponseBindingResult(
fieldError.getDefaultMessage(),
fieldError.getField(),
Objects.requireNonNull(fieldError.getRejectedValue()).toString(),
fieldError.getCode()
))
.collect(Collectors.toList());
}
}
이런식으로 bindingResult의 getFieldErrors() 메서드를 통해 List 타입으로 받아서 내가 필요한 부분들을 뽑아내서 커스텀하여 자바 객체의 형태로 다시 반환하면 된다.
그럼 BidingResult를 직접 보내는 것이 아닌 @ResponseBody 애노테이션 덕분에 자바 객체는 JSON으로 직렬화가 되어서 내가 원하는 에러 형태로 반환되며 내가 원하는 형태로 에러 응답을 보낼 수 있게 된다.
BindingResult에 걸려서 반환된 에러 정보를 담은 DTO
'프로젝트 이슈 및 몰랐던점 정리 > CommunityAPI' 카테고리의 다른 글
[트러블 슈팅] ⚠️ Spring Boot LocalDateTime 변환 에러 해결법 (@JsonFormat vs @DateTimeFormat) (0) | 2025.03.09 |
---|---|
[트러블 슈팅] ⚠️ @RequestBody로 MultipartFile을 받을 수 없는 이유와 해결법(@RequestPart) (0) | 2025.03.09 |
[학습 포인트] 💡 JPA에서 update 시 @Modifying 애노테이션이 필요한 이유 (0) | 2025.03.09 |
[트러블 슈팅] Spring HATEOAS - 단일 리소스에 대한 API 엔드 포인트 제공 (0) | 2024.11.28 |
[트러블 슈팅] JPA - LazyInitializationException과 N+1 (1) | 2024.11.27 |