BridgeMethodResolver properly resolves interface hierarchies

Issue: SPR-16103
This commit is contained in:
Juergen Hoeller
2017-10-24 01:01:49 +02:00
parent 55b0c2f243
commit 182da15908
2 changed files with 160 additions and 91 deletions

View File

@@ -138,43 +138,13 @@ public abstract class BridgeMethodResolver {
return (method != null && isResolvedTypeMatch(method, candidateMethod, declaringClass));
}
/**
* Searches for the generic {@link Method} declaration whose erased signature
* matches that of the supplied bridge method.
* @throws IllegalStateException if the generic declaration cannot be found
*/
@Nullable
private static Method findGenericDeclaration(Method bridgeMethod) {
// Search parent types for method that has same signature as bridge.
Class<?> superclass = bridgeMethod.getDeclaringClass().getSuperclass();
while (superclass != null && Object.class != superclass) {
Method method = searchForMatch(superclass, bridgeMethod);
if (method != null && !method.isBridge()) {
return method;
}
superclass = superclass.getSuperclass();
}
// Search interfaces.
Class<?>[] interfaces = ClassUtils.getAllInterfacesForClass(bridgeMethod.getDeclaringClass());
for (Class<?> ifc : interfaces) {
Method method = searchForMatch(ifc, bridgeMethod);
if (method != null && !method.isBridge()) {
return method;
}
}
return null;
}
/**
* Returns {@code true} if the {@link Type} signature of both the supplied
* {@link Method#getGenericParameterTypes() generic Method} and concrete {@link Method}
* are equal after resolving all types against the declaringType, otherwise
* returns {@code false}.
*/
private static boolean isResolvedTypeMatch(
Method genericMethod, Method candidateMethod, Class<?> declaringClass) {
private static boolean isResolvedTypeMatch(Method genericMethod, Method candidateMethod, Class<?> declaringClass) {
Type[] genericParameters = genericMethod.getGenericParameterTypes();
Class<?>[] candidateParameters = candidateMethod.getParameterTypes();
if (genericParameters.length != candidateParameters.length) {
@@ -197,6 +167,41 @@ public abstract class BridgeMethodResolver {
return true;
}
/**
* Searches for the generic {@link Method} declaration whose erased signature
* matches that of the supplied bridge method.
* @throws IllegalStateException if the generic declaration cannot be found
*/
@Nullable
private static Method findGenericDeclaration(Method bridgeMethod) {
// Search parent types for method that has same signature as bridge.
Class<?> superclass = bridgeMethod.getDeclaringClass().getSuperclass();
while (superclass != null && Object.class != superclass) {
Method method = searchForMatch(superclass, bridgeMethod);
if (method != null && !method.isBridge()) {
return method;
}
superclass = superclass.getSuperclass();
}
Class<?>[] interfaces = ClassUtils.getAllInterfacesForClass(bridgeMethod.getDeclaringClass());
return searchInterfaces(interfaces, bridgeMethod);
}
@Nullable
private static Method searchInterfaces(Class<?>[] interfaces, Method bridgeMethod) {
for (Class<?> ifc : interfaces) {
Method method = searchForMatch(ifc, bridgeMethod);
if (method != null && !method.isBridge()) {
return method;
}
else {
return searchInterfaces(ifc.getInterfaces(), bridgeMethod);
}
}
return null;
}
/**
* If the supplied {@link Class} has a declared {@link Method} whose signature matches
* that of the supplied {@link Method}, then this matching {@link Method} is returned,
@@ -204,7 +209,12 @@ public abstract class BridgeMethodResolver {
*/
@Nullable
private static Method searchForMatch(Class<?> type, Method bridgeMethod) {
return ReflectionUtils.findMethod(type, bridgeMethod.getName(), bridgeMethod.getParameterTypes());
try {
return type.getDeclaredMethod(bridgeMethod.getName(), bridgeMethod.getParameterTypes());
}
catch (NoSuchMethodException ex) {
return null;
}
}
/**