Skip to content

Commit 3c22404

Browse files
committed
Fix RuntimeHintsAgent instrumentation for method invocation
Prior to this commit, the `RuntimeHintsAgent` would instrument `Method.invoke` in a way that fails when invoked methods are not public. This commit ensures that before delegating the invocation call, the instrumentation makes the method accessible before delegating the call. Fixes gh-29046
1 parent f877f81 commit 3c22404

File tree

2 files changed

+38
-2
lines changed

2 files changed

+38
-2
lines changed

integration-tests/src/test/java/org/springframework/aot/RuntimeHintsAgentTests.java

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,11 +54,14 @@ public class RuntimeHintsAgentTests {
5454

5555
private static Method toStringMethod;
5656

57+
private static Method privateGreetMethod;
58+
5759

5860
@BeforeAll
5961
public static void classSetup() throws NoSuchMethodException {
6062
defaultConstructor = String.class.getConstructor();
6163
toStringMethod = String.class.getMethod("toString");
64+
privateGreetMethod = PrivateClass.class.getDeclaredMethod("greet");
6265
}
6366

6467

@@ -79,6 +82,7 @@ private static Stream<Arguments> instrumentedReflectionMethods() {
7982
Class.forName("java.lang.String");
8083
}
8184
catch (ClassNotFoundException e) {
85+
throw new RuntimeException(e);
8286
}
8387
}, MethodReference.of(Class.class, "forName")),
8488
Arguments.of((Runnable) () -> String.class.getClasses(), MethodReference.of(Class.class, "getClasses")),
@@ -87,6 +91,7 @@ private static Stream<Arguments> instrumentedReflectionMethods() {
8791
String.class.getConstructor();
8892
}
8993
catch (NoSuchMethodException e) {
94+
throw new RuntimeException(e);
9095
}
9196
}, MethodReference.of(Class.class, "getConstructor")),
9297
Arguments.of((Runnable) () -> String.class.getConstructors(), MethodReference.of(Class.class, "getConstructors")),
@@ -96,14 +101,16 @@ private static Stream<Arguments> instrumentedReflectionMethods() {
96101
String.class.getDeclaredConstructor();
97102
}
98103
catch (NoSuchMethodException e) {
104+
throw new RuntimeException(e);
99105
}
100106
}, MethodReference.of(Class.class, "getDeclaredConstructor")),
101107
Arguments.of((Runnable) () -> String.class.getDeclaredConstructors(), MethodReference.of(Class.class, "getDeclaredConstructors")),
102108
Arguments.of((Runnable) () -> {
103109
try {
104-
String.class.getDeclaredField("test");
110+
String.class.getDeclaredField("value");
105111
}
106112
catch (NoSuchFieldException e) {
113+
throw new RuntimeException(e);
107114
}
108115
}, MethodReference.of(Class.class, "getDeclaredField")),
109116
Arguments.of((Runnable) () -> String.class.getDeclaredFields(), MethodReference.of(Class.class, "getDeclaredFields")),
@@ -112,12 +119,13 @@ private static Stream<Arguments> instrumentedReflectionMethods() {
112119
String.class.getDeclaredMethod("toString");
113120
}
114121
catch (NoSuchMethodException e) {
122+
throw new RuntimeException(e);
115123
}
116124
}, MethodReference.of(Class.class, "getDeclaredMethod")),
117125
Arguments.of((Runnable) () -> String.class.getDeclaredMethods(), MethodReference.of(Class.class, "getDeclaredMethods")),
118126
Arguments.of((Runnable) () -> {
119127
try {
120-
String.class.getField("test");
128+
String.class.getField("value");
121129
}
122130
catch (NoSuchFieldException e) {
123131
}
@@ -128,6 +136,7 @@ private static Stream<Arguments> instrumentedReflectionMethods() {
128136
String.class.getMethod("toString");
129137
}
130138
catch (NoSuchMethodException e) {
139+
throw new RuntimeException(e);
131140
}
132141
}, MethodReference.of(Class.class, "getMethod")),
133142
Arguments.of((Runnable) () -> String.class.getMethods(), MethodReference.of(Class.class, "getMethods")),
@@ -136,20 +145,31 @@ private static Stream<Arguments> instrumentedReflectionMethods() {
136145
classLoader.loadClass("java.lang.String");
137146
}
138147
catch (ClassNotFoundException e) {
148+
throw new RuntimeException(e);
139149
}
140150
}, MethodReference.of(ClassLoader.class, "loadClass")),
141151
Arguments.of((Runnable) () -> {
142152
try {
143153
defaultConstructor.newInstance();
144154
}
145155
catch (Exception e) {
156+
throw new RuntimeException(e);
146157
}
147158
}, MethodReference.of(Constructor.class, "newInstance")),
148159
Arguments.of((Runnable) () -> {
149160
try {
150161
toStringMethod.invoke("");
151162
}
152163
catch (Exception e) {
164+
throw new RuntimeException(e);
165+
}
166+
}, MethodReference.of(Method.class, "invoke")),
167+
Arguments.of((Runnable) () -> {
168+
try {
169+
privateGreetMethod.invoke(new PrivateClass());
170+
}
171+
catch (Exception e) {
172+
throw new RuntimeException(e);
153173
}
154174
}, MethodReference.of(Method.class, "invoke"))
155175
);
@@ -265,4 +285,12 @@ Stream<RecordedInvocation> recordedInvocations(HintType hintType) {
265285

266286
}
267287

288+
private static class PrivateClass {
289+
290+
private String greet() {
291+
return "hello";
292+
}
293+
294+
}
295+
268296
}

spring-core-test/src/main/java/org/springframework/aot/agent/InstrumentedBridgeMethods.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -337,13 +337,21 @@ public static Object constructornewInstance(Constructor<?> constructor, Object..
337337

338338
public static Object methodinvoke(Method method, Object object, Object... arguments) throws InvocationTargetException, IllegalAccessException {
339339
Object result = null;
340+
boolean accessibilityChanged = false;
340341
try {
342+
if (!Modifier.isPublic(method.getModifiers())) {
343+
method.setAccessible(true);
344+
accessibilityChanged = true;
345+
}
341346
result = method.invoke(object, arguments);
342347
}
343348
finally {
344349
RecordedInvocation invocation = RecordedInvocation.of(InstrumentedMethod.METHOD_INVOKE)
345350
.onInstance(method).withArguments(object, arguments).returnValue(result).build();
346351
RecordedInvocationsPublisher.publish(invocation);
352+
if (accessibilityChanged) {
353+
method.setAccessible(false);
354+
}
347355
}
348356
return result;
349357
}

0 commit comments

Comments
 (0)