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.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ConcurrentReferenceHashMap;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
import org.springframework.util.ReflectionUtils.MethodFilter;
|
||||
|
||||
/**
|
||||
* Helper for resolving synthetic {@link Method#isBridge bridge Methods} to the
|
||||
|
|
@ -47,6 +50,8 @@ import org.springframework.util.ReflectionUtils;
|
|||
*/
|
||||
public final class BridgeMethodResolver {
|
||||
|
||||
private static final Map<Method, Method> cache = new ConcurrentReferenceHashMap<>();
|
||||
|
||||
private BridgeMethodResolver() {
|
||||
}
|
||||
|
||||
|
|
@ -64,32 +69,26 @@ public final class BridgeMethodResolver {
|
|||
if (!bridgeMethod.isBridge()) {
|
||||
return bridgeMethod;
|
||||
}
|
||||
|
||||
// Gather all methods with matching name and parameter size.
|
||||
List<Method> candidateMethods = new ArrayList<>();
|
||||
Method[] methods = ReflectionUtils.getAllDeclaredMethods(bridgeMethod.getDeclaringClass());
|
||||
for (Method candidateMethod : methods) {
|
||||
if (isBridgedCandidateFor(candidateMethod, bridgeMethod)) {
|
||||
candidateMethods.add(candidateMethod);
|
||||
Method bridgedMethod = cache.get(bridgeMethod);
|
||||
if (bridgedMethod == null) {
|
||||
// Gather all methods with matching name and parameter size.
|
||||
List<Method> candidateMethods = new ArrayList<>();
|
||||
MethodFilter filter = candidateMethod ->
|
||||
isBridgedCandidateFor(candidateMethod, bridgeMethod);
|
||||
ReflectionUtils.doWithMethods(bridgeMethod.getDeclaringClass(), candidateMethods::add, filter);
|
||||
if (!candidateMethods.isEmpty()) {
|
||||
bridgedMethod = candidateMethods.size() == 1 ?
|
||||
candidateMethods.get(0) :
|
||||
searchCandidates(candidateMethods, bridgeMethod);
|
||||
}
|
||||
if (bridgedMethod == null) {
|
||||
// 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...
|
||||
bridgedMethod = bridgeMethod;
|
||||
}
|
||||
cache.put(bridgeMethod, bridgedMethod);
|
||||
}
|
||||
|
||||
// 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.
|
||||
// Let's proceed with the passed-in method and hope for the best...
|
||||
return bridgeMethod;
|
||||
}
|
||||
return bridgedMethod;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
Loading…
Reference in New Issue