Cache "no match" result from ExceptionHandler methods

Closes gh-26339
This commit is contained in:
Rossen Stoyanchev
2021-01-08 18:04:22 +00:00
parent 234b4719c6
commit 689b5566bf
2 changed files with 43 additions and 7 deletions

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2019 the original author or authors. * Copyright 2002-2021 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -38,6 +38,19 @@ import org.springframework.util.ConcurrentReferenceHashMap;
*/ */
public abstract class AbstractExceptionHandlerMethodResolver { public abstract class AbstractExceptionHandlerMethodResolver {
private static final Method NO_MATCHING_EXCEPTION_HANDLER_METHOD;
static {
try {
NO_MATCHING_EXCEPTION_HANDLER_METHOD =
AbstractExceptionHandlerMethodResolver.class.getDeclaredMethod("noMatchingExceptionHandler");
}
catch (NoSuchMethodException ex) {
throw new IllegalStateException("Expected method not found: " + ex);
}
}
private final Map<Class<? extends Throwable>, Method> mappedMethods = new HashMap<>(16); private final Map<Class<? extends Throwable>, Method> mappedMethods = new HashMap<>(16);
private final Map<Class<? extends Throwable>, Method> exceptionLookupCache = new ConcurrentReferenceHashMap<>(16); private final Map<Class<? extends Throwable>, Method> exceptionLookupCache = new ConcurrentReferenceHashMap<>(16);
@@ -110,7 +123,7 @@ public abstract class AbstractExceptionHandlerMethodResolver {
method = getMappedMethod(exceptionType); method = getMappedMethod(exceptionType);
this.exceptionLookupCache.put(exceptionType, method); this.exceptionLookupCache.put(exceptionType, method);
} }
return method; return (method != NO_MATCHING_EXCEPTION_HANDLER_METHOD ? method : null);
} }
/** /**
@@ -129,8 +142,14 @@ public abstract class AbstractExceptionHandlerMethodResolver {
return this.mappedMethods.get(matches.get(0)); return this.mappedMethods.get(matches.get(0));
} }
else { else {
return null; return NO_MATCHING_EXCEPTION_HANDLER_METHOD;
} }
} }
/**
* For the NO_MATCHING_EXCEPTION_HANDLER_METHOD constant.
*/
private void noMatchingExceptionHandler() {
}
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2020 the original author or authors. * Copyright 2002-2021 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -49,6 +49,18 @@ public class ExceptionHandlerMethodResolver {
public static final MethodFilter EXCEPTION_HANDLER_METHODS = method -> public static final MethodFilter EXCEPTION_HANDLER_METHODS = method ->
AnnotatedElementUtils.hasAnnotation(method, ExceptionHandler.class); AnnotatedElementUtils.hasAnnotation(method, ExceptionHandler.class);
private static final Method NO_MATCHING_EXCEPTION_HANDLER_METHOD;
static {
try {
NO_MATCHING_EXCEPTION_HANDLER_METHOD =
ExceptionHandlerMethodResolver.class.getDeclaredMethod("noMatchingExceptionHandler");
}
catch (NoSuchMethodException ex) {
throw new IllegalStateException("Expected method not found: " + ex);
}
}
private final Map<Class<? extends Throwable>, Method> mappedMethods = new HashMap<>(16); private final Map<Class<? extends Throwable>, Method> mappedMethods = new HashMap<>(16);
@@ -153,13 +165,12 @@ public class ExceptionHandlerMethodResolver {
method = getMappedMethod(exceptionType); method = getMappedMethod(exceptionType);
this.exceptionLookupCache.put(exceptionType, method); this.exceptionLookupCache.put(exceptionType, method);
} }
return method; return (method != NO_MATCHING_EXCEPTION_HANDLER_METHOD ? method : null);
} }
/** /**
* Return the {@link Method} mapped to the given exception type, or {@code null} if none. * Return the {@link Method} mapped to the given exception type, or {@code null} if none.
*/ */
@Nullable
private Method getMappedMethod(Class<? extends Throwable> exceptionType) { private Method getMappedMethod(Class<? extends Throwable> exceptionType) {
List<Class<? extends Throwable>> matches = new ArrayList<>(); List<Class<? extends Throwable>> matches = new ArrayList<>();
for (Class<? extends Throwable> mappedException : this.mappedMethods.keySet()) { for (Class<? extends Throwable> mappedException : this.mappedMethods.keySet()) {
@@ -172,8 +183,14 @@ public class ExceptionHandlerMethodResolver {
return this.mappedMethods.get(matches.get(0)); return this.mappedMethods.get(matches.get(0));
} }
else { else {
return null; return NO_MATCHING_EXCEPTION_HANDLER_METHOD;
} }
} }
/**
* For the NO_MATCHING_EXCEPTION_HANDLER_METHOD constant.
*/
private void noMatchingExceptionHandler() {
}
} }