Spring Boot 2.7.3
Java 11.0.9
@Valid
어노테이션을 사용해서@NotNull
)를 이용해 요청으로 받은 application/json 데이터를 검사// 예시
public ResponseEntity<String> postComment(@RequestBody @Valid CommentDto commentDto) {
// ...
}
// 예시
public class RequestDto {
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public static class CommentDto {
@NotNull
private Boolean isPublic;
private String text;
}
}
MethodArgumentNotValidException
예외가 발생하기 때문에{
"text": "abc"
}
.m.m.a.ExceptionHandlerExceptionResolver : Resolved [org.springframework.web.bind.MethodArgumentNotValidException: Validation failed for argument [1] in public {Response_Return_Type} {Controller_Method}: [Field error in object '{DTO}' on field '{Field_Name}': rejected value [null]; codes [NotNull.requestDto.mobileIsPublic,NotNull.{Field_Name},NotNull.java.lang.Boolean,NotNull]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [{DTO}.{Field_Name}]; arguments []; default message [{Field_Name}]]; default message [널이어서는 안됩니다]] ]
- Response_Return_Type: org.springframework.http.ResponseEntity<java.lang.String>
- Controller_Method: postComment(CommentDto)
- DTO: CommentDto
- Field_Name: isPublic(예외 발생 원인)
@RestControllerAdvice
어노테이션을 사용한 GlobalExceptionHandler를 이용해 예외 처리를 해준 상태였다.// 예시
public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<ErrorResponse> handleArgumentNotValidException(MethodArgumentNotValidException ex) {
return ResponseEntity
.status(HttpStatus.BAD_REQUEST); // 400 상태 코드 반환
}
}
BeanCreationException
발생org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'handlerExceptionResolver' defined in class path resource [org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfiguration$EnableWebMvcConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.web.servlet.HandlerExceptionResolver]: Factory method 'handlerExceptionResolver' threw exception; nested exception is java.lang.IllegalStateException: Ambiguous @ExceptionHandler method mapped for [class org.springframework.web.bind.MethodArgumentNotValidException]: {public org.springframework.http.ResponseEntity {프로젝트명}.GlobalExceptionHandler.handleArgumentNotValidException(org.springframework.web.bind.MethodArgumentNotValidException), public final org.springframework.http.ResponseEntity org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler.handleException(java.lang.Exception,org.springframework.web.context.request.WebRequest) throws java.lang.Exception}
@ExceptionHandler
에 이미 MethodArgumentNotValidException
이 구현되어있기 때문에 GlobalExceptionHandler에서 동일한 예외 처리를 하게 되면, Ambiguous(모호성) 문제가 발생한다. 즉, MethodArgumentNotValidException
예외에 대해 어떤 방법을 사용해야 할 지 모르게 된다.
@ExceptionHandler
어노테이션을 사용하는 대신, 해당 핸들러(handleMethodArgumentNotValid
)를 직접 오버라이드해서 사용한다.@RestControllerAdvice
public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {
@Override
protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException ex,
HttpHeaders headers,
HttpStatus status,
WebRequest request) {
return super.handleMethodArgumentNotValid(ex, headers, status, request);
}
public enum ErrorCode {
VALIDATION_FAILED(HttpStatus.BAD_REQUEST, "Validation failed for argument");
private final HttpStatus httpStatus;
private final String message;
@Getter
public class ErrorResponse {
private final LocalDateTime timestamp = LocalDateTime.now();
private final int statusCode;
private final String error;
private final String message;
public ErrorResponse(ErrorCode errorCode) {
this.statusCode = errorCode.getHttpStatus().value();
this.error = errorCode.getHttpStatus().name();
this.message = errorCode.getMessage();
}
}
handleMethodArgumentNotValid
핸들러를 아래와 같이 작성했습니다. // Bean Validation 예외 발생시
@Override
protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
ErrorCode errorCode = ErrorCode.VALIDATION_FAILED;
return ResponseEntity.status(errorCode.getHttpStatus())
.body(new ErrorResponse(errorCode));
}
덕분에 에러 해결했습니다. 감사합니다.