@RestControllerAdvice
public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {
private static final Logger log = LoggerFactory.getLogger("ErrorLogger");
private static final String LOG_FORMAT_INFO = "\n[🔵INFO] - ({} {})\n(id: {}, role: {})\n{}\n {}: {}";
private static final String LOG_FORMAT_WARN = "\n[🟠WARN] - ({} {})\n(id: {}, role: {})";
private static final String LOG_FORMAT_ERROR = "\n[🔴ERROR] - ({} {})\n(id: {}, role: {})";
@ExceptionHandler(SaphyException.class)
public ApiResponse<Void> handle(SaphyException exception, HttpServletRequest request) {
logInfo(exception, request);
return new ApiResponse<>(exception);
}
private void logInfo(SaphyException exception, HttpServletRequest request) {
log.info(LOG_FORMAT_INFO, request.getMethod(), request.getRequestURI(), exception.getErrorCode(), exception.getClass().getName(), exception.getMessage());
}
@ExceptionHandler(MethodArgumentNotValidException.class) // MethodArgumentNotValidException 예외가 발생했을 때 아래 메소드를 실행
public String processValidationError(MethodArgumentNotValidException exception) {
BindingResult bindingResult = exception.getBindingResult();
StringBuilder builder = new StringBuilder();
for (FieldError fieldError : bindingResult.getFieldErrors()) {
builder.append("[");
builder.append(fieldError.getField());
builder.append("]의 값이 잘못됐습니다. ");
builder.append("입력된 값: [");
builder.append(fieldError.getRejectedValue());
builder.append("]");
}
return builder.toString();
}
}
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]: Failed to instantiate
[org.springframework.web.servlet.HandlerExceptionResolver]: Factory method 'handlerExceptionResolver' threw exception with message:
Ambiguous @ExceptionHandler method mapped for [class org.springframework.web.bind.MethodArgumentNotValidException]:
{public java.lang.String saphy.saphy.global.handler.GlobalExceptionHandler.processValidationError(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.class)
메서드가 중복되어 발생하는 문제입니다.
구체적으로, 상속받은 ResponseEntityExceptionHandler
클래스는 이미 MethodArgumentNotValidException
을 포함한 여러 일반적인 예외들에 대한 처리 메서드를 구현하고 있습니다.
따라서 GlobalExceptionHandler
가ResponseEntityExceptionHandler
를 상속받고 있는 상황에서, 동일한 예외에 대한 @ExceptionHandler(MethodArgumentNotValidException.class)
메서드를 추가로 정의하면 중복 처리 문제가 발생하는 것입니다.
MethodArgumentNotValidException
을 처리하는 메서드를 ResponseEntityExceptionHandler
의 handleMethodArgumentNotValid
메서드를 오버라이드하는 것으로 변경하면 됩니다. 이렇게 하면 Spring의 기본 예외 처리와 충돌하지 않기 때문이죠.
@RestControllerAdvice
public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {
private static final Logger log = LoggerFactory.getLogger("ErrorLogger");
private static final String LOG_FORMAT_INFO = "\n[🔵INFO] - ({} {})\n(id: {}, role: {})\n{}\n {}: {}";
private static final String LOG_FORMAT_WARN = "\n[🟠WARN] - ({} {})\n(id: {}, role: {})";
private static final String LOG_FORMAT_ERROR = "\n[🔴ERROR] - ({} {})\n(id: {}, role: {})";
@ExceptionHandler(SaphyException.class)
public ApiResponse<Void> handle(SaphyException exception, HttpServletRequest request) {
logInfo(exception, request);
return new ApiResponse<>(exception);
}
private void logInfo(SaphyException exception, HttpServletRequest request) {
log.info(LOG_FORMAT_INFO, request.getMethod(), request.getRequestURI(), exception.getErrorCode(), exception.getClass().getName(), exception.getMessage());
}
// ------ 수정된 부분 --------
@Override
protected ResponseEntity<Object> handleMethodArgumentNotValid(
MethodArgumentNotValidException ex,
HttpHeaders headers,
HttpStatusCode status,
WebRequest request) {
BindingResult bindingResult = ex.getBindingResult();
StringBuilder builder = new StringBuilder();
for (FieldError fieldError : bindingResult.getFieldErrors()) {
builder.append("[");
builder.append(fieldError.getField());
builder.append("]의 값이 잘못됐습니다. ");
builder.append("입력된 값: [");
builder.append(fieldError.getRejectedValue());
builder.append("]");
}
ApiResponse<String> apiResponse = new ApiResponse<>(builder.toString());
return new ResponseEntity<>(apiResponse, headers, status);
}
// ------ 수정된 부분 --------
}