ReflectiveMethodExecutor invokes interface method if possible

Issue: SPR-16845
This commit is contained in:
Juergen Hoeller
2018-07-19 16:35:59 +02:00
parent 478d7255d2
commit c4df335a1d
4 changed files with 67 additions and 40 deletions

View File

@@ -885,7 +885,7 @@ public abstract class ClassUtils {
public static Class<?> getUserClass(Class<?> clazz) {
if (clazz.getName().contains(CGLIB_CLASS_SEPARATOR)) {
Class<?> superclass = clazz.getSuperclass();
if (superclass != null && Object.class != superclass) {
if (superclass != null && superclass != Object.class) {
return superclass;
}
}
@@ -1244,10 +1244,11 @@ public abstract class ClassUtils {
* access (e.g. calls to {@code Class#getDeclaredMethods} etc, this implementation
* will fall back to returning the originally provided method.
* @param method the method to be invoked, which may come from an interface
* @param targetClass the target class for the current invocation.
* May be {@code null} or may not even implement the method.
* @param targetClass the target class for the current invocation
* (may be {@code null} or may not even implement the method)
* @return the specific target method, or the original method if the
* {@code targetClass} doesn't implement it or is {@code null}
* {@code targetClass} does not implement it
* @see #getInterfaceMethodIfPossible
*/
public static Method getMostSpecificMethod(Method method, @Nullable Class<?> targetClass) {
if (targetClass != null && targetClass != method.getDeclaringClass() && isOverridable(method, targetClass)) {
@@ -1273,6 +1274,34 @@ public abstract class ClassUtils {
return method;
}
/**
* Determine a corresponding interface method for the given method handle, if possible.
* <p>This is particularly useful for arriving at a public exported type on Jigsaw
* which can be reflectively invoked without an illegal access warning.
* @param method the method to be invoked, potentially from an implementation class
* @return the corresponding interface method, or the original method if none found
* @since 5.1
* @see #getMostSpecificMethod
*/
public static Method getInterfaceMethodIfPossible(Method method) {
if (Modifier.isPublic(method.getModifiers()) && !method.getDeclaringClass().isInterface()) {
Class<?> current = method.getDeclaringClass();
while (current != null && current != Object.class) {
Class<?>[] ifcs = current.getInterfaces();
for (Class<?> ifc : ifcs) {
try {
return ifc.getMethod(method.getName(), method.getParameterTypes());
}
catch (NoSuchMethodException ex) {
// ignore
}
}
current = current.getSuperclass();
}
}
return method;
}
/**
* Determine whether the given method is declared by the user or at least pointing to
* a user-declared method.