Cache BridgeMethodResolver results
Add a cache to `BridgeMethodResolver` to help with repeated calls to resolve the same methods. Since bridge method resolution can be somewhat expensive (especially when resolving generics), and the number of bridge methods is quite small, a cache generally helps. This commit also simplifies the code a little by calling `doWithMethods` directly rather than relying on `ReflectionUtils.getAllDeclaredMethods` to do so. The methods list is now always created, but we save the list creation that `getAllDeclaredMethods` used to do. Closes gh-22579
This commit is contained in:
parent
a57d6ba5f3
commit
db8eaec131
|
|
@ -21,10 +21,13 @@ import java.lang.reflect.Type;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import org.springframework.lang.Nullable;
|
import org.springframework.lang.Nullable;
|
||||||
import org.springframework.util.ClassUtils;
|
import org.springframework.util.ClassUtils;
|
||||||
|
import org.springframework.util.ConcurrentReferenceHashMap;
|
||||||
import org.springframework.util.ReflectionUtils;
|
import org.springframework.util.ReflectionUtils;
|
||||||
|
import org.springframework.util.ReflectionUtils.MethodFilter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper for resolving synthetic {@link Method#isBridge bridge Methods} to the
|
* Helper for resolving synthetic {@link Method#isBridge bridge Methods} to the
|
||||||
|
|
@ -47,6 +50,8 @@ import org.springframework.util.ReflectionUtils;
|
||||||
*/
|
*/
|
||||||
public final class BridgeMethodResolver {
|
public final class BridgeMethodResolver {
|
||||||
|
|
||||||
|
private static final Map<Method, Method> cache = new ConcurrentReferenceHashMap<>();
|
||||||
|
|
||||||
private BridgeMethodResolver() {
|
private BridgeMethodResolver() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -64,32 +69,26 @@ public final class BridgeMethodResolver {
|
||||||
if (!bridgeMethod.isBridge()) {
|
if (!bridgeMethod.isBridge()) {
|
||||||
return bridgeMethod;
|
return bridgeMethod;
|
||||||
}
|
}
|
||||||
|
Method bridgedMethod = cache.get(bridgeMethod);
|
||||||
|
if (bridgedMethod == null) {
|
||||||
// Gather all methods with matching name and parameter size.
|
// Gather all methods with matching name and parameter size.
|
||||||
List<Method> candidateMethods = new ArrayList<>();
|
List<Method> candidateMethods = new ArrayList<>();
|
||||||
Method[] methods = ReflectionUtils.getAllDeclaredMethods(bridgeMethod.getDeclaringClass());
|
MethodFilter filter = candidateMethod ->
|
||||||
for (Method candidateMethod : methods) {
|
isBridgedCandidateFor(candidateMethod, bridgeMethod);
|
||||||
if (isBridgedCandidateFor(candidateMethod, bridgeMethod)) {
|
ReflectionUtils.doWithMethods(bridgeMethod.getDeclaringClass(), candidateMethods::add, filter);
|
||||||
candidateMethods.add(candidateMethod);
|
if (!candidateMethods.isEmpty()) {
|
||||||
|
bridgedMethod = candidateMethods.size() == 1 ?
|
||||||
|
candidateMethods.get(0) :
|
||||||
|
searchCandidates(candidateMethods, bridgeMethod);
|
||||||
}
|
}
|
||||||
}
|
if (bridgedMethod == null) {
|
||||||
|
|
||||||
// Now perform simple quick check.
|
|
||||||
if (candidateMethods.size() == 1) {
|
|
||||||
return candidateMethods.get(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Search for candidate match.
|
|
||||||
Method bridgedMethod = searchCandidates(candidateMethods, bridgeMethod);
|
|
||||||
if (bridgedMethod != null) {
|
|
||||||
// Bridged method found...
|
|
||||||
return bridgedMethod;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// A bridge method was passed in but we couldn't find the bridged method.
|
// A bridge method was passed in but we couldn't find the bridged method.
|
||||||
// Let's proceed with the passed-in method and hope for the best...
|
// Let's proceed with the passed-in method and hope for the best...
|
||||||
return bridgeMethod;
|
bridgedMethod = bridgeMethod;
|
||||||
}
|
}
|
||||||
|
cache.put(bridgeMethod, bridgedMethod);
|
||||||
|
}
|
||||||
|
return bridgedMethod;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue