[에러 해결] BeanCreationException: Error creating bean with name 'handlerExceptionResolver' defined in class path resource

김진형·2024년 9월 21일
0

에러 발생 코드

@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을 포함한 여러 일반적인 예외들에 대한 처리 메서드를 구현하고 있습니다.

따라서 GlobalExceptionHandlerResponseEntityExceptionHandler를 상속받고 있는 상황에서, 동일한 예외에 대한 @ExceptionHandler(MethodArgumentNotValidException.class) 메서드를 추가로 정의하면 중복 처리 문제가 발생하는 것입니다.

에러 해결하기

MethodArgumentNotValidException을 처리하는 메서드를 ResponseEntityExceptionHandlerhandleMethodArgumentNotValid 메서드를 오버라이드하는 것으로 변경하면 됩니다. 이렇게 하면 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);
	}
    
    // ------ 수정된 부분 --------

}

0개의 댓글