Skip to content

Commit 287d244

Browse files
committed
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
1 parent 65e6334 commit 287d244

File tree

1 file changed

+23
-24
lines changed

1 file changed

+23
-24
lines changed

spring-core/src/main/java/org/springframework/core/BridgeMethodResolver.java

Lines changed: 23 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,13 @@
2121
import java.util.ArrayList;
2222
import java.util.Arrays;
2323
import java.util.List;
24+
import java.util.Map;
2425

2526
import org.springframework.lang.Nullable;
2627
import org.springframework.util.ClassUtils;
28+
import org.springframework.util.ConcurrentReferenceHashMap;
2729
import org.springframework.util.ReflectionUtils;
30+
import org.springframework.util.ReflectionUtils.MethodFilter;
2831

2932
/**
3033
* Helper for resolving synthetic {@link Method#isBridge bridge Methods} to the
@@ -47,6 +50,8 @@
4750
*/
4851
public final class BridgeMethodResolver {
4952

53+
private static final Map<Method, Method> cache = new ConcurrentReferenceHashMap<>();
54+
5055
private BridgeMethodResolver() {
5156
}
5257

@@ -64,32 +69,26 @@ public static Method findBridgedMethod(Method bridgeMethod) {
6469
if (!bridgeMethod.isBridge()) {
6570
return bridgeMethod;
6671
}
67-
68-
// Gather all methods with matching name and parameter size.
69-
List<Method> candidateMethods = new ArrayList<>();
70-
Method[] methods = ReflectionUtils.getAllDeclaredMethods(bridgeMethod.getDeclaringClass());
71-
for (Method candidateMethod : methods) {
72-
if (isBridgedCandidateFor(candidateMethod, bridgeMethod)) {
73-
candidateMethods.add(candidateMethod);
72+
Method bridgedMethod = cache.get(bridgeMethod);
73+
if (bridgedMethod == null) {
74+
// Gather all methods with matching name and parameter size.
75+
List<Method> candidateMethods = new ArrayList<>();
76+
MethodFilter filter = candidateMethod ->
77+
isBridgedCandidateFor(candidateMethod, bridgeMethod);
78+
ReflectionUtils.doWithMethods(bridgeMethod.getDeclaringClass(), candidateMethods::add, filter);
79+
if (!candidateMethods.isEmpty()) {
80+
bridgedMethod = candidateMethods.size() == 1 ?
81+
candidateMethods.get(0) :
82+
searchCandidates(candidateMethods, bridgeMethod);
7483
}
84+
if (bridgedMethod == null) {
85+
// A bridge method was passed in but we couldn't find the bridged method.
86+
// Let's proceed with the passed-in method and hope for the best...
87+
bridgedMethod = bridgeMethod;
88+
}
89+
cache.put(bridgeMethod, bridgedMethod);
7590
}
76-
77-
// Now perform simple quick check.
78-
if (candidateMethods.size() == 1) {
79-
return candidateMethods.get(0);
80-
}
81-
82-
// Search for candidate match.
83-
Method bridgedMethod = searchCandidates(candidateMethods, bridgeMethod);
84-
if (bridgedMethod != null) {
85-
// Bridged method found...
86-
return bridgedMethod;
87-
}
88-
else {
89-
// A bridge method was passed in but we couldn't find the bridged method.
90-
// Let's proceed with the passed-in method and hope for the best...
91-
return bridgeMethod;
92-
}
91+
return bridgedMethod;
9392
}
9493

9594
/**

0 commit comments

Comments
 (0)