Merge branch '6.2.x'
Build and Deploy Snapshot / Build and Deploy Snapshot (push) Waiting to run Details
Build and Deploy Snapshot / Verify (push) Blocked by required conditions Details
Deploy Docs / Dispatch docs deployment (push) Waiting to run Details

This commit is contained in:
Juergen Hoeller 2025-07-11 22:50:47 +02:00
commit 64de254b58
13 changed files with 69 additions and 44 deletions

View File

@ -16,6 +16,7 @@
package org.springframework.aop.aspectj;
import java.lang.reflect.InaccessibleObjectException;
import java.lang.reflect.InvocationTargetException;
import org.jspecify.annotations.Nullable;
@ -67,7 +68,7 @@ public class SimpleAspectInstanceFactory implements AspectInstanceFactory {
throw new AopConfigException(
"Unable to instantiate aspect class: " + this.aspectClass.getName(), ex);
}
catch (IllegalAccessException ex) {
catch (IllegalAccessException | InaccessibleObjectException ex) {
throw new AopConfigException(
"Could not access aspect constructor: " + this.aspectClass.getName(), ex);
}

View File

@ -16,6 +16,7 @@
package org.springframework.aop.support;
import java.lang.reflect.InaccessibleObjectException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
@ -366,7 +367,7 @@ public abstract class AopUtils {
throw new AopInvocationException("AOP configuration seems to be invalid: tried calling method [" +
method + "] on target [" + target + "]", ex);
}
catch (IllegalAccessException ex) {
catch (IllegalAccessException | InaccessibleObjectException ex) {
throw new AopInvocationException("Could not access method [" + method + "]", ex);
}
}

View File

@ -17,6 +17,7 @@
package org.springframework.beans;
import java.lang.reflect.Field;
import java.lang.reflect.InaccessibleObjectException;
import java.util.HashMap;
import java.util.Map;
@ -142,7 +143,7 @@ public class DirectFieldAccessor extends AbstractNestablePropertyAccessor {
ReflectionUtils.makeAccessible(this.field);
return this.field.get(getWrappedInstance());
}
catch (IllegalAccessException ex) {
catch (IllegalAccessException | InaccessibleObjectException ex) {
throw new InvalidPropertyException(getWrappedClass(),
this.field.getName(), "Field is not accessible", ex);
}
@ -154,7 +155,7 @@ public class DirectFieldAccessor extends AbstractNestablePropertyAccessor {
ReflectionUtils.makeAccessible(this.field);
this.field.set(getWrappedInstance(), value);
}
catch (IllegalAccessException ex) {
catch (IllegalAccessException | InaccessibleObjectException ex) {
throw new InvalidPropertyException(getWrappedClass(), this.field.getName(),
"Field is not accessible", ex);
}

View File

@ -17,6 +17,7 @@
package org.springframework.beans.factory.support;
import java.lang.reflect.Constructor;
import java.lang.reflect.InaccessibleObjectException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.function.Supplier;
@ -167,7 +168,7 @@ public class SimpleInstantiationStrategy implements InstantiationStrategy {
"Illegal arguments to factory method '" + factoryMethod.getName() + "'; " +
"args: " + StringUtils.arrayToCommaDelimitedString(args), ex);
}
catch (IllegalAccessException ex) {
catch (IllegalAccessException | InaccessibleObjectException ex) {
throw new BeanInstantiationException(factoryMethod,
"Cannot access factory method '" + factoryMethod.getName() + "'; is it public?", ex);
}

View File

@ -16,6 +16,7 @@
package org.springframework.context.event;
import java.lang.reflect.InaccessibleObjectException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
@ -366,8 +367,8 @@ public class ApplicationListenerMethodAdapter implements GenericApplicationListe
return null;
}
ReflectionUtils.makeAccessible(this.method);
try {
ReflectionUtils.makeAccessible(this.method);
if (KotlinDetector.isSuspendingFunction(this.method)) {
return CoroutinesUtils.invokeSuspendingFunction(this.method, bean, args);
}
@ -377,7 +378,7 @@ public class ApplicationListenerMethodAdapter implements GenericApplicationListe
assertTargetBean(this.method, bean, args);
throw new IllegalStateException(getInvocationErrorMessage(bean, ex.getMessage(), args), ex);
}
catch (IllegalAccessException ex) {
catch (IllegalAccessException | InaccessibleObjectException ex) {
throw new IllegalStateException(getInvocationErrorMessage(bean, ex.getMessage(), args), ex);
}
catch (InvocationTargetException ex) {

View File

@ -16,6 +16,7 @@
package org.springframework.scheduling.annotation;
import java.lang.reflect.InaccessibleObjectException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;
@ -173,7 +174,7 @@ abstract class ScheduledAnnotationReactiveSupport {
"Cannot obtain a Publisher-convertible value from the @Scheduled reactive method",
ex.getTargetException());
}
catch (IllegalAccessException ex) {
catch (IllegalAccessException | InaccessibleObjectException ex) {
throw new IllegalArgumentException(
"Cannot obtain a Publisher-convertible value from the @Scheduled reactive method", ex);
}

View File

@ -17,6 +17,7 @@
package org.springframework.scripting.groovy;
import java.io.IOException;
import java.lang.reflect.InaccessibleObjectException;
import java.lang.reflect.InvocationTargetException;
import groovy.lang.GroovyClassLoader;
@ -331,7 +332,7 @@ public class GroovyScriptFactory implements ScriptFactory, BeanFactoryAware, Bea
throw new ScriptCompilationException(
scriptSource, "Unable to instantiate Groovy script class: " + scriptClass.getName(), ex);
}
catch (IllegalAccessException ex) {
catch (IllegalAccessException | InaccessibleObjectException ex) {
throw new ScriptCompilationException(
scriptSource, "Could not access Groovy script constructor: " + scriptClass.getName(), ex);
}

View File

@ -17,6 +17,7 @@
package org.springframework.scripting.support;
import java.io.IOException;
import java.lang.reflect.InaccessibleObjectException;
import java.lang.reflect.InvocationTargetException;
import javax.script.Invocable;
@ -167,7 +168,7 @@ public class StandardScriptFactory implements ScriptFactory, BeanClassLoaderAwar
throw new ScriptCompilationException(
scriptSource, "Unable to instantiate script class: " + scriptClass.getName(), ex);
}
catch (IllegalAccessException ex) {
catch (IllegalAccessException | InaccessibleObjectException ex) {
throw new ScriptCompilationException(
scriptSource, "Could not access script constructor: " + scriptClass.getName(), ex);
}

View File

@ -17,6 +17,7 @@
package org.springframework.util;
import java.io.Serializable;
import java.lang.reflect.InaccessibleObjectException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
@ -305,7 +306,7 @@ public class AutoPopulatingList<E> implements List<E>, Serializable {
throw new ElementInstantiationException(
"Unable to instantiate element class: " + this.elementClass.getName(), ex);
}
catch (IllegalAccessException ex) {
catch (IllegalAccessException | InaccessibleObjectException ex) {
throw new ElementInstantiationException(
"Could not access element constructor: " + this.elementClass.getName(), ex);
}

View File

@ -1466,10 +1466,8 @@ public abstract class ClassUtils {
}
/**
* Get the first publicly accessible method in the supplied method's type hierarchy that
* Get the highest publicly accessible method in the supplied method's type hierarchy that
* has a method signature equivalent to the supplied method, if possible.
* <p>If the supplied method is {@code public} and declared in a {@code public} type,
* the supplied method will be returned.
* <p>Otherwise, this method recursively searches the class hierarchy and implemented
* interfaces for an equivalent method that is {@code public} and declared in a
* {@code public} type.
@ -1492,19 +1490,23 @@ public abstract class ClassUtils {
* @see #getMostSpecificMethod(Method, Class)
*/
public static Method getPubliclyAccessibleMethodIfPossible(Method method, @Nullable Class<?> targetClass) {
Class<?> declaringClass = method.getDeclaringClass();
// If the method is not public, we can abort the search immediately; or if the method's
// declaring class is public, the method is already publicly accessible.
if (!Modifier.isPublic(method.getModifiers()) || Modifier.isPublic(declaringClass.getModifiers())) {
// If the method is not public, we can abort the search immediately.
if (!Modifier.isPublic(method.getModifiers())) {
return method;
}
Method interfaceMethod = getInterfaceMethodIfPossible(method, targetClass, true);
// If we found a method in a public interface, return the interface method.
if (!interfaceMethod.equals(method)) {
if (interfaceMethod != method) {
return interfaceMethod;
}
Class<?> declaringClass = method.getDeclaringClass();
// Bypass cache for java.lang.Object unless it is actually an overridable method declared there.
if (declaringClass.getSuperclass() == Object.class && !ReflectionUtils.isObjectMethod(method)) {
return method;
}
Method result = publiclyAccessibleMethodCache.computeIfAbsent(method,
key -> findPubliclyAccessibleMethodIfPossible(key.getName(), key.getParameterTypes(), declaringClass));
return (result != null ? result : method);
@ -1513,19 +1515,19 @@ public abstract class ClassUtils {
private static @Nullable Method findPubliclyAccessibleMethodIfPossible(
String methodName, Class<?>[] parameterTypes, Class<?> declaringClass) {
Method result = null;
Class<?> current = declaringClass.getSuperclass();
while (current != null) {
if (Modifier.isPublic(current.getModifiers())) {
try {
return current.getDeclaredMethod(methodName, parameterTypes);
}
catch (NoSuchMethodException ex) {
// ignore
}
Method method = getMethodOrNull(current, methodName, parameterTypes);
if (method == null) {
break;
}
current = current.getSuperclass();
if (Modifier.isPublic(method.getDeclaringClass().getModifiers())) {
result = method;
}
current = method.getDeclaringClass().getSuperclass();
}
return null;
return result;
}
/**

View File

@ -16,6 +16,7 @@
package org.springframework.util;
import java.lang.reflect.InaccessibleObjectException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
@ -169,7 +170,8 @@ public class MethodInvoker {
@Nullable Object[] arguments = getArguments();
Class<?>[] argTypes = new Class<?>[arguments.length];
for (int i = 0; i < arguments.length; ++i) {
argTypes[i] = (arguments[i] != null ? arguments[i].getClass() : Object.class);
Object argument = arguments[i];
argTypes[i] = (argument != null ? argument.getClass() : Object.class);
}
// Try to get the exact method first.
@ -268,8 +270,20 @@ public class MethodInvoker {
if (targetObject == null && !Modifier.isStatic(preparedMethod.getModifiers())) {
throw new IllegalArgumentException("Target method must not be non-static without a target");
}
ReflectionUtils.makeAccessible(preparedMethod);
return preparedMethod.invoke(targetObject, getArguments());
try {
ReflectionUtils.makeAccessible(preparedMethod);
return preparedMethod.invoke(targetObject, getArguments());
}
catch (IllegalAccessException | InaccessibleObjectException ex) {
if (targetObject != null) {
Method fallbackMethod =
ClassUtils.getPubliclyAccessibleMethodIfPossible(preparedMethod, targetObject.getClass());
if (fallbackMethod != preparedMethod) {
return fallbackMethod.invoke(targetObject, getArguments());
}
}
throw ex;
}
}
@ -296,12 +310,13 @@ public class MethodInvoker {
public static int getTypeDifferenceWeight(Class<?>[] paramTypes, @Nullable Object[] args) {
int result = 0;
for (int i = 0; i < paramTypes.length; i++) {
if (!ClassUtils.isAssignableValue(paramTypes[i], args[i])) {
Class<?> paramType = paramTypes[i];
Object arg = args[i];
if (!ClassUtils.isAssignableValue(paramType, arg)) {
return Integer.MAX_VALUE;
}
if (args[i] != null) {
Class<?> paramType = paramTypes[i];
Class<?> superClass = args[i].getClass().getSuperclass();
if (arg != null) {
Class<?> superClass = arg.getClass().getSuperclass();
while (superClass != null) {
if (paramType.equals(superClass)) {
result = result + 2;

View File

@ -687,13 +687,13 @@ class ClassUtilsTests {
}
@Test
void publicMethodInPublicClass() throws Exception {
void publicMethodInObjectClass() throws Exception {
Class<?> originalType = String.class;
Method originalMethod = originalType.getDeclaredMethod("toString");
Method originalMethod = originalType.getDeclaredMethod("hashCode");
Method publiclyAccessibleMethod = ClassUtils.getPubliclyAccessibleMethodIfPossible(originalMethod, null);
assertThat(publiclyAccessibleMethod.getDeclaringClass()).isEqualTo(originalType);
assertThat(publiclyAccessibleMethod).isSameAs(originalMethod);
assertThat(publiclyAccessibleMethod.getDeclaringClass()).isEqualTo(Object.class);
assertThat(publiclyAccessibleMethod.getName()).isEqualTo("hashCode");
assertPubliclyAccessible(publiclyAccessibleMethod);
}
@ -703,9 +703,9 @@ class ClassUtilsTests {
Method originalMethod = originalType.getDeclaredMethod("size");
Method publiclyAccessibleMethod = ClassUtils.getPubliclyAccessibleMethodIfPossible(originalMethod, null);
// Should not find the interface method in List.
assertThat(publiclyAccessibleMethod.getDeclaringClass()).isEqualTo(originalType);
assertThat(publiclyAccessibleMethod).isSameAs(originalMethod);
// Should find the interface method in List.
assertThat(publiclyAccessibleMethod.getDeclaringClass()).isEqualTo(List.class);
assertThat(publiclyAccessibleMethod.getName()).isEqualTo("size");
assertPubliclyAccessible(publiclyAccessibleMethod);
}

View File

@ -17,7 +17,6 @@
package org.springframework.test.context.bean.override.convention;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Objects;
@ -59,7 +58,7 @@ final class TestBeanOverrideHandler extends BeanOverrideHandler {
ReflectionUtils.makeAccessible(this.factoryMethod);
return this.factoryMethod.invoke(null);
}
catch (IllegalAccessException | InvocationTargetException ex) {
catch (Throwable ex) {
throw new IllegalStateException(
"Failed to invoke @TestBean factory method: " + this.factoryMethod, ex);
}