ControllerAdviceExceptionResolver.java
package sprout.mvc.advice;
import com.fasterxml.jackson.databind.ObjectMapper;
import sprout.beans.annotation.Component;
import sprout.beans.annotation.Order;
import sprout.mvc.exception.ExceptionResolver;
import sprout.mvc.http.*;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Optional;
@Component
@Order(0)
public class ControllerAdviceExceptionResolver implements ExceptionResolver {
private final ControllerAdviceRegistry controllerAdviceRegistry;
private final List<ResponseResolver> responseResolvers;
private final ObjectMapper objectMapper;
public ControllerAdviceExceptionResolver(ControllerAdviceRegistry controllerAdviceRegistry, List<ResponseResolver> responseResolvers, ObjectMapper objectMapper) {
this.controllerAdviceRegistry = controllerAdviceRegistry;
this.responseResolvers = responseResolvers;
this.objectMapper = objectMapper;
}
@Override
public Object resolveException(HttpRequest<?> request, HttpResponse response, Object handlerMethod, Exception exception) {
Optional<ExceptionHandlerObject> handlerOptional = controllerAdviceRegistry.getExceptionHandler(exception.getClass());
if (handlerOptional.isPresent()) {
ExceptionHandlerObject exceptionHandler = handlerOptional.get();
try {
Method handlerMethodRef = exceptionHandler.getMethod();
Object handlerInstance = exceptionHandler.getBean();
Object handlerReturnValue;
// 예외 핸들러 메서드 시그니처 분석 및 호출
int paramCount = handlerMethodRef.getParameterCount();
Class<?>[] paramTypes = handlerMethodRef.getParameterTypes();
if (paramCount == 0) {
handlerReturnValue = handlerMethodRef.invoke(handlerInstance);
} else if (paramCount == 1 && paramTypes[0].isAssignableFrom(exception.getClass())) {
handlerReturnValue = handlerMethodRef.invoke(handlerInstance, exception);
} else if (paramCount == 2) {
if (paramTypes[0].isAssignableFrom(exception.getClass()) && paramTypes[1].isAssignableFrom(HttpRequest.class)) {
handlerReturnValue = handlerMethodRef.invoke(handlerInstance, exception, request);
} else if (paramTypes[0].isAssignableFrom(HttpRequest.class) && paramTypes[1].isAssignableFrom(exception.getClass())) {
handlerReturnValue = handlerMethodRef.invoke(handlerInstance, request, exception);
} else {
System.err.println("Unsupported @ExceptionHandler method signature: " + handlerMethodRef.getName());
return null; // 처리 못 함
}
} else {
System.err.println("Unsupported @ExceptionHandler method signature: " + handlerMethodRef.getName());
return null; // 처리 못 함
}
// 예외 핸들러의 반환 값을 ResponseResolver를 통해 처리
for (ResponseResolver resolver : responseResolvers) {
if (resolver.supports(handlerReturnValue)) {
ResponseEntity<?> responseEntity = resolver.resolve(handlerReturnValue, request);
response.setResponseEntity(responseEntity);
return new Object(); // 처리 완료를 의미하는 임의의 객체 반환 (null이 아님)
}
}
System.err.println("No suitable ResponseResolver found for @ExceptionHandler return value: " + handlerReturnValue);
return null; // 처리 못 함
} catch (InvocationTargetException ie) {
System.err.println("Exception in @ExceptionHandler itself: " + ie.getTargetException().getMessage());
ie.getTargetException().printStackTrace();
} catch (IllegalAccessException | IllegalArgumentException iae) {
System.err.println("Error invoking @ExceptionHandler: " + iae.getMessage());
iae.printStackTrace();
}
}
return null; // 이 ExceptionResolver가 예외를 처리하지 못했음을 알림
}
}