Restore behavior for ClassUtils.getInterfaceMethodIfPossible()
Commit47f88e123fintroduced support for invoking init/destroy/SpEL methods via public types whenever possible. To achieve that, getInterfaceMethodIfPossible() was modified so that it only returned interface methods from public interfaces; however, we have learned that third parties relied on the previous behavior which found any interface method (even in non-public interfaces). In light of the above, this commit partially reverts commit47f88e123fin order to reinstate getInterfaceMethodIfPossible() in non-deprecated form with its previous behavior. See gh-33216
This commit is contained in:
@@ -135,11 +135,18 @@ public abstract class ClassUtils {
|
||||
private static final Set<Class<?>> javaLanguageInterfaces;
|
||||
|
||||
/**
|
||||
* Cache for equivalent methods on a public interface implemented by the declaring class.
|
||||
* <p>A {@code null} value signals that no public interface method was found for the key.
|
||||
* Cache for equivalent methods on a interface implemented by the declaring class.
|
||||
* <p>A {@code null} value signals that no interface method was found for the key.
|
||||
*/
|
||||
private static final Map<Method, Method> interfaceMethodCache = new ConcurrentReferenceHashMap<>(256);
|
||||
|
||||
/**
|
||||
* Cache for equivalent methods on a public interface implemented by the declaring class.
|
||||
* <p>A {@code null} value signals that no public interface method was found for the key.
|
||||
* @since 6.2
|
||||
*/
|
||||
private static final Map<Method, Method> publicInterfaceMethodCache = new ConcurrentReferenceHashMap<>(256);
|
||||
|
||||
/**
|
||||
* Cache for equivalent public methods in a public declaring type within the type hierarchy
|
||||
* of the method's declaring class.
|
||||
@@ -1403,7 +1410,8 @@ public abstract class ClassUtils {
|
||||
* @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
|
||||
* @deprecated in favor of {@link #getPubliclyAccessibleMethodIfPossible(Method, Class)}
|
||||
* @see #getPubliclyAccessibleMethodIfPossible(Method, Class)
|
||||
* @deprecated in favor of {@link #getInterfaceMethodIfPossible(Method, Class)}
|
||||
*/
|
||||
@Deprecated
|
||||
public static Method getInterfaceMethodIfPossible(Method method) {
|
||||
@@ -1421,38 +1429,45 @@ public abstract class ClassUtils {
|
||||
* @since 5.3.16
|
||||
* @see #getPubliclyAccessibleMethodIfPossible(Method, Class)
|
||||
* @see #getMostSpecificMethod
|
||||
* @deprecated in favor of {@link #getPubliclyAccessibleMethodIfPossible(Method, Class)}
|
||||
*/
|
||||
@Deprecated(since = "6.2")
|
||||
public static Method getInterfaceMethodIfPossible(Method method, @Nullable Class<?> targetClass) {
|
||||
return getInterfaceMethodIfPossible(method, targetClass, false);
|
||||
}
|
||||
|
||||
private static Method getInterfaceMethodIfPossible(Method method, @Nullable Class<?> targetClass,
|
||||
boolean requirePublicInterface) {
|
||||
|
||||
Class<?> declaringClass = method.getDeclaringClass();
|
||||
if (!Modifier.isPublic(method.getModifiers()) || declaringClass.isInterface()) {
|
||||
if (!Modifier.isPublic(method.getModifiers()) || (declaringClass.isInterface() &&
|
||||
(!requirePublicInterface || Modifier.isPublic(declaringClass.getModifiers())))) {
|
||||
return method;
|
||||
}
|
||||
String methodName = method.getName();
|
||||
Class<?>[] parameterTypes = method.getParameterTypes();
|
||||
|
||||
Map<Method, Method> methodCache = (requirePublicInterface ? publicInterfaceMethodCache : interfaceMethodCache);
|
||||
// Try cached version of method in its declaring class
|
||||
Method result = interfaceMethodCache.computeIfAbsent(method,
|
||||
key -> findInterfaceMethodIfPossible(methodName, parameterTypes, declaringClass, Object.class));
|
||||
Method result = methodCache.computeIfAbsent(method, key -> findInterfaceMethodIfPossible(
|
||||
methodName, parameterTypes, declaringClass, Object.class, requirePublicInterface));
|
||||
if (result == null && targetClass != null) {
|
||||
// No interface method found yet -> try given target class (possibly a subclass of the
|
||||
// declaring class, late-binding a base class method to a subclass-declared interface:
|
||||
// see e.g. HashMap.HashIterator.hasNext)
|
||||
result = findInterfaceMethodIfPossible(methodName, parameterTypes, targetClass, declaringClass);
|
||||
result = findInterfaceMethodIfPossible(
|
||||
methodName, parameterTypes, targetClass, declaringClass, requirePublicInterface);
|
||||
}
|
||||
return (result != null ? result : method);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static Method findInterfaceMethodIfPossible(String methodName, Class<?>[] parameterTypes,
|
||||
Class<?> startClass, Class<?> endClass) {
|
||||
Class<?> startClass, Class<?> endClass, boolean requirePublicInterface) {
|
||||
|
||||
Class<?> current = startClass;
|
||||
while (current != null && current != endClass) {
|
||||
for (Class<?> ifc : current.getInterfaces()) {
|
||||
try {
|
||||
if (Modifier.isPublic(ifc.getModifiers())) {
|
||||
if (!requirePublicInterface || Modifier.isPublic(ifc.getModifiers())) {
|
||||
return ifc.getMethod(methodName, parameterTypes);
|
||||
}
|
||||
}
|
||||
@@ -1500,7 +1515,7 @@ public abstract class ClassUtils {
|
||||
return method;
|
||||
}
|
||||
|
||||
Method interfaceMethod = getInterfaceMethodIfPossible(method, targetClass);
|
||||
Method interfaceMethod = getInterfaceMethodIfPossible(method, targetClass, true);
|
||||
// If we found a method in a public interface, return the interface method.
|
||||
if (!interfaceMethod.equals(method)) {
|
||||
return interfaceMethod;
|
||||
|
||||
Reference in New Issue
Block a user