|
|
|
@ -29,7 +29,6 @@ import org.jspecify.annotations.Nullable; |
|
|
|
import org.springframework.util.ClassUtils; |
|
|
|
import org.springframework.util.ClassUtils; |
|
|
|
import org.springframework.util.ConcurrentReferenceHashMap; |
|
|
|
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 |
|
|
|
@ -115,8 +114,8 @@ public final class BridgeMethodResolver { |
|
|
|
if (bridgedMethod == null) { |
|
|
|
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<>(); |
|
|
|
MethodFilter filter = (candidateMethod -> isBridgedCandidateFor(candidateMethod, bridgeMethod)); |
|
|
|
ReflectionUtils.doWithMethods(userClass, candidateMethods::add, |
|
|
|
ReflectionUtils.doWithMethods(userClass, candidateMethods::add, filter); |
|
|
|
candidateMethod -> isBridgedCandidateFor(candidateMethod, bridgeMethod)); |
|
|
|
if (!candidateMethods.isEmpty()) { |
|
|
|
if (!candidateMethods.isEmpty()) { |
|
|
|
bridgedMethod = (candidateMethods.size() == 1 ? candidateMethods.get(0) : |
|
|
|
bridgedMethod = (candidateMethods.size() == 1 ? candidateMethods.get(0) : |
|
|
|
searchCandidates(candidateMethods, bridgeMethod, targetClass)); |
|
|
|
searchCandidates(candidateMethods, bridgeMethod, targetClass)); |
|
|
|
@ -152,9 +151,6 @@ public final class BridgeMethodResolver { |
|
|
|
private static @Nullable Method searchCandidates( |
|
|
|
private static @Nullable Method searchCandidates( |
|
|
|
List<Method> candidateMethods, Method bridgeMethod, Class<?> targetClass) { |
|
|
|
List<Method> candidateMethods, Method bridgeMethod, Class<?> targetClass) { |
|
|
|
|
|
|
|
|
|
|
|
if (candidateMethods.isEmpty()) { |
|
|
|
|
|
|
|
return null; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
Method previousMethod = null; |
|
|
|
Method previousMethod = null; |
|
|
|
boolean sameSig = true; |
|
|
|
boolean sameSig = true; |
|
|
|
for (Method candidateMethod : candidateMethods) { |
|
|
|
for (Method candidateMethod : candidateMethods) { |
|
|
|
@ -204,18 +200,16 @@ public final class BridgeMethodResolver { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private static boolean checkResolvedTypeMatch(Method genericMethod, Method candidateMethod, Class<?> clazz) { |
|
|
|
private static boolean checkResolvedTypeMatch(Method genericMethod, Method candidateMethod, Class<?> clazz) { |
|
|
|
|
|
|
|
// First, compare return type.
|
|
|
|
|
|
|
|
ResolvableType genericReturnType = ResolvableType.forMethodReturnType(genericMethod, clazz); |
|
|
|
|
|
|
|
if (!ClassUtils.resolvePrimitiveIfNecessary(candidateMethod.getReturnType()).equals( |
|
|
|
|
|
|
|
ClassUtils.resolvePrimitiveIfNecessary(genericReturnType.toClass()))) { |
|
|
|
|
|
|
|
return false; |
|
|
|
|
|
|
|
} |
|
|
|
Class<?>[] candidateParameters = candidateMethod.getParameterTypes(); |
|
|
|
Class<?>[] candidateParameters = candidateMethod.getParameterTypes(); |
|
|
|
for (int i = 0; i < candidateParameters.length; i++) { |
|
|
|
for (int i = 0; i < candidateParameters.length; i++) { |
|
|
|
ResolvableType genericParameter = ResolvableType.forMethodParameter(genericMethod, i, clazz); |
|
|
|
ResolvableType genericParameter = ResolvableType.forMethodParameter(genericMethod, i, clazz); |
|
|
|
Class<?> candidateParameter = candidateParameters[i]; |
|
|
|
if (!ClassUtils.resolvePrimitiveIfNecessary(candidateParameters[i]).equals( |
|
|
|
if (candidateParameter.isArray()) { |
|
|
|
|
|
|
|
// An array type: compare the component type.
|
|
|
|
|
|
|
|
if (!candidateParameter.componentType().equals(genericParameter.getComponentType().toClass())) { |
|
|
|
|
|
|
|
return false; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
// A non-array type: compare the type itself.
|
|
|
|
|
|
|
|
if (!ClassUtils.resolvePrimitiveIfNecessary(candidateParameter).equals( |
|
|
|
|
|
|
|
ClassUtils.resolvePrimitiveIfNecessary(genericParameter.toClass()))) { |
|
|
|
ClassUtils.resolvePrimitiveIfNecessary(genericParameter.toClass()))) { |
|
|
|
return false; |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
|