cc.shacocloud.mirage.web.ExceptionHandlerMethodResolver Maven / Gradle / Ivy
package cc.shacocloud.mirage.web;
import cc.shacocloud.mirage.web.bind.annotation.ExceptionHandler;
import io.vertx.core.Future;
import lombok.Getter;
import org.springframework.core.ExceptionDepthComparator;
import org.springframework.core.MethodIntrospector;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.annotation.OrderUtils;
import org.jetbrains.annotations.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ConcurrentReferenceHashMap;
import org.springframework.util.ReflectionUtils.MethodFilter;
import java.lang.reflect.Method;
import java.util.*;
/**
* 异常处理方法解析。
* 在给定的类中发现表示注解{@linkplain ExceptionHandler}的方法,
* 包含它的所有超类,并帮助将给定的{@link Exception}解析为给定的{@link Method}支持的异常类型。
*/
public class ExceptionHandlerMethodResolver implements Ordered {
/**
* 用于选择{@code @ExceptionHandler}方法的过滤器。
*/
public static final MethodFilter EXCEPTION_HANDLER_METHODS = method -> AnnotatedElementUtils.hasAnnotation(method, ExceptionHandler.class);
private final Map, Method> mappedMethods = new HashMap<>(32);
private final Map, Method> exceptionLookupCache = new ConcurrentReferenceHashMap<>(16);
@Getter
private final Object exceptionHandler;
/**
* 查找给定类型中的{@link ExceptionHandler}方法的构造函数。
*/
public ExceptionHandlerMethodResolver(Object exceptionHandler) {
Class> handlerType = exceptionHandler.getClass();
for (Method method : MethodIntrospector.selectMethods(handlerType, EXCEPTION_HANDLER_METHODS)) {
for (Class extends Throwable> exceptionType : detectExceptionMappings(method)) {
addExceptionMapping(exceptionType, method);
}
}
this.exceptionHandler = exceptionHandler;
}
/**
* 首先从{@code @ExceptionHandler}注解中提取异常映射, 然后作为方法签名本身的回退。
*/
@SuppressWarnings("unchecked")
private List> detectExceptionMappings(Method method) {
List> result = new ArrayList<>();
detectAnnotationExceptionMappings(method, result);
if (result.isEmpty()) {
for (Class> paramType : method.getParameterTypes()) {
if (Throwable.class.isAssignableFrom(paramType)) {
result.add((Class extends Throwable>) paramType);
}
}
}
if (result.isEmpty()) {
throw new IllegalStateException("没有映射到的异常类型: " + method);
}
return result;
}
private void detectAnnotationExceptionMappings(Method method, List> result) {
ExceptionHandler ann = AnnotatedElementUtils.findMergedAnnotation(method, ExceptionHandler.class);
Assert.state(ann != null, "没有@ExceptionHandler注解");
Assert.isAssignable(Future.class, method.getReturnType(),
"异常处理器[" + method.getDeclaringClass() + "]声明的方法[" + method.toString() + "]不合法," +
"@ExceptionHandler 注解标识的方法返回值必须是 io.vertx.core.Future或其子类! 实际类型");
result.addAll(Arrays.asList(ann.value()));
}
private void addExceptionMapping(Class extends Throwable> exceptionType, Method method) {
Method oldMethod = this.mappedMethods.put(exceptionType, method);
if (oldMethod != null && !oldMethod.equals(method)) {
throw new IllegalStateException("不明确的 @ExceptionHandler 注解方法映射: [" + exceptionType + "]: {" + oldMethod + ", " + method + "}");
}
}
/**
* 所包含的类型是否有异常映射。
*/
public boolean hasExceptionMappings() {
return !this.mappedMethods.isEmpty();
}
/**
* 找到一个{@link Method}来处理给定的异常。
* 如果找到多个匹配项,使用{@link ExceptionDepthComparator}
*
* @param exception 异常
* @return 处理异常的方法;如果没有找到异常,则使用{@code null}
*/
@Nullable
public Method resolveMethod(Exception exception) {
return resolveMethodByThrowable(exception);
}
/**
* 找到一个{@link Method}来处理给定的 {@link Throwable}
* 如果找到多个匹配项,使用{@link ExceptionDepthComparator}
*
* @param exception 异常
* @return 处理异常的方法;如果没有找到异常,则使用{@code null}
*/
@Nullable
public Method resolveMethodByThrowable(Throwable exception) {
Method method = resolveMethodByExceptionType(exception.getClass());
if (method == null) {
Throwable cause = exception.getCause();
if (cause != null) {
method = resolveMethodByExceptionType(cause.getClass());
}
}
return method;
}
/**
* 找到一个{@link Method}来处理给定的异常类型。
*
* @param exceptionType 异常类型
* @return 处理异常的方法;如果没有找到异常,则使用{@code null}
*/
@Nullable
public Method resolveMethodByExceptionType(Class extends Throwable> exceptionType) {
Method method = this.exceptionLookupCache.get(exceptionType);
if (method == null) {
method = getMappedMethod(exceptionType);
if (method != null) {
this.exceptionLookupCache.put(exceptionType, method);
}
}
return method;
}
/**
* 返回映射到给定异常类型的{@link Method},如果没有,则返回{@code null}。
*/
@Nullable
private Method getMappedMethod(Class extends Throwable> exceptionType) {
List> matches = new ArrayList<>();
for (Class extends Throwable> mappedException : this.mappedMethods.keySet()) {
if (mappedException.isAssignableFrom(exceptionType)) {
matches.add(mappedException);
}
}
if (!matches.isEmpty()) {
matches.sort(new ExceptionDepthComparator(exceptionType));
return this.mappedMethods.get(matches.get(0));
} else {
return null;
}
}
@Override
public int getOrder() {
return OrderUtils.getOrder(exceptionHandler.getClass(), 0);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy