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
This commit is contained in:
parent
f877f81ae4
commit
3c22404bce
|
@ -54,11 +54,14 @@ public class RuntimeHintsAgentTests {
|
||||||
|
|
||||||
private static Method toStringMethod;
|
private static Method toStringMethod;
|
||||||
|
|
||||||
|
private static Method privateGreetMethod;
|
||||||
|
|
||||||
|
|
||||||
@BeforeAll
|
@BeforeAll
|
||||||
public static void classSetup() throws NoSuchMethodException {
|
public static void classSetup() throws NoSuchMethodException {
|
||||||
defaultConstructor = String.class.getConstructor();
|
defaultConstructor = String.class.getConstructor();
|
||||||
toStringMethod = String.class.getMethod("toString");
|
toStringMethod = String.class.getMethod("toString");
|
||||||
|
privateGreetMethod = PrivateClass.class.getDeclaredMethod("greet");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -79,6 +82,7 @@ public class RuntimeHintsAgentTests {
|
||||||
Class.forName("java.lang.String");
|
Class.forName("java.lang.String");
|
||||||
}
|
}
|
||||||
catch (ClassNotFoundException e) {
|
catch (ClassNotFoundException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
}, MethodReference.of(Class.class, "forName")),
|
}, MethodReference.of(Class.class, "forName")),
|
||||||
Arguments.of((Runnable) () -> String.class.getClasses(), MethodReference.of(Class.class, "getClasses")),
|
Arguments.of((Runnable) () -> String.class.getClasses(), MethodReference.of(Class.class, "getClasses")),
|
||||||
|
@ -87,6 +91,7 @@ public class RuntimeHintsAgentTests {
|
||||||
String.class.getConstructor();
|
String.class.getConstructor();
|
||||||
}
|
}
|
||||||
catch (NoSuchMethodException e) {
|
catch (NoSuchMethodException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
}, MethodReference.of(Class.class, "getConstructor")),
|
}, MethodReference.of(Class.class, "getConstructor")),
|
||||||
Arguments.of((Runnable) () -> String.class.getConstructors(), MethodReference.of(Class.class, "getConstructors")),
|
Arguments.of((Runnable) () -> String.class.getConstructors(), MethodReference.of(Class.class, "getConstructors")),
|
||||||
|
@ -96,14 +101,16 @@ public class RuntimeHintsAgentTests {
|
||||||
String.class.getDeclaredConstructor();
|
String.class.getDeclaredConstructor();
|
||||||
}
|
}
|
||||||
catch (NoSuchMethodException e) {
|
catch (NoSuchMethodException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
}, MethodReference.of(Class.class, "getDeclaredConstructor")),
|
}, MethodReference.of(Class.class, "getDeclaredConstructor")),
|
||||||
Arguments.of((Runnable) () -> String.class.getDeclaredConstructors(), MethodReference.of(Class.class, "getDeclaredConstructors")),
|
Arguments.of((Runnable) () -> String.class.getDeclaredConstructors(), MethodReference.of(Class.class, "getDeclaredConstructors")),
|
||||||
Arguments.of((Runnable) () -> {
|
Arguments.of((Runnable) () -> {
|
||||||
try {
|
try {
|
||||||
String.class.getDeclaredField("test");
|
String.class.getDeclaredField("value");
|
||||||
}
|
}
|
||||||
catch (NoSuchFieldException e) {
|
catch (NoSuchFieldException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
}, MethodReference.of(Class.class, "getDeclaredField")),
|
}, MethodReference.of(Class.class, "getDeclaredField")),
|
||||||
Arguments.of((Runnable) () -> String.class.getDeclaredFields(), MethodReference.of(Class.class, "getDeclaredFields")),
|
Arguments.of((Runnable) () -> String.class.getDeclaredFields(), MethodReference.of(Class.class, "getDeclaredFields")),
|
||||||
|
@ -112,12 +119,13 @@ public class RuntimeHintsAgentTests {
|
||||||
String.class.getDeclaredMethod("toString");
|
String.class.getDeclaredMethod("toString");
|
||||||
}
|
}
|
||||||
catch (NoSuchMethodException e) {
|
catch (NoSuchMethodException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
}, MethodReference.of(Class.class, "getDeclaredMethod")),
|
}, MethodReference.of(Class.class, "getDeclaredMethod")),
|
||||||
Arguments.of((Runnable) () -> String.class.getDeclaredMethods(), MethodReference.of(Class.class, "getDeclaredMethods")),
|
Arguments.of((Runnable) () -> String.class.getDeclaredMethods(), MethodReference.of(Class.class, "getDeclaredMethods")),
|
||||||
Arguments.of((Runnable) () -> {
|
Arguments.of((Runnable) () -> {
|
||||||
try {
|
try {
|
||||||
String.class.getField("test");
|
String.class.getField("value");
|
||||||
}
|
}
|
||||||
catch (NoSuchFieldException e) {
|
catch (NoSuchFieldException e) {
|
||||||
}
|
}
|
||||||
|
@ -128,6 +136,7 @@ public class RuntimeHintsAgentTests {
|
||||||
String.class.getMethod("toString");
|
String.class.getMethod("toString");
|
||||||
}
|
}
|
||||||
catch (NoSuchMethodException e) {
|
catch (NoSuchMethodException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
}, MethodReference.of(Class.class, "getMethod")),
|
}, MethodReference.of(Class.class, "getMethod")),
|
||||||
Arguments.of((Runnable) () -> String.class.getMethods(), MethodReference.of(Class.class, "getMethods")),
|
Arguments.of((Runnable) () -> String.class.getMethods(), MethodReference.of(Class.class, "getMethods")),
|
||||||
|
@ -136,6 +145,7 @@ public class RuntimeHintsAgentTests {
|
||||||
classLoader.loadClass("java.lang.String");
|
classLoader.loadClass("java.lang.String");
|
||||||
}
|
}
|
||||||
catch (ClassNotFoundException e) {
|
catch (ClassNotFoundException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
}, MethodReference.of(ClassLoader.class, "loadClass")),
|
}, MethodReference.of(ClassLoader.class, "loadClass")),
|
||||||
Arguments.of((Runnable) () -> {
|
Arguments.of((Runnable) () -> {
|
||||||
|
@ -143,6 +153,7 @@ public class RuntimeHintsAgentTests {
|
||||||
defaultConstructor.newInstance();
|
defaultConstructor.newInstance();
|
||||||
}
|
}
|
||||||
catch (Exception e) {
|
catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
}, MethodReference.of(Constructor.class, "newInstance")),
|
}, MethodReference.of(Constructor.class, "newInstance")),
|
||||||
Arguments.of((Runnable) () -> {
|
Arguments.of((Runnable) () -> {
|
||||||
|
@ -150,6 +161,15 @@ public class RuntimeHintsAgentTests {
|
||||||
toStringMethod.invoke("");
|
toStringMethod.invoke("");
|
||||||
}
|
}
|
||||||
catch (Exception e) {
|
catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}, MethodReference.of(Method.class, "invoke")),
|
||||||
|
Arguments.of((Runnable) () -> {
|
||||||
|
try {
|
||||||
|
privateGreetMethod.invoke(new PrivateClass());
|
||||||
|
}
|
||||||
|
catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
}, MethodReference.of(Method.class, "invoke"))
|
}, MethodReference.of(Method.class, "invoke"))
|
||||||
);
|
);
|
||||||
|
@ -265,4 +285,12 @@ public class RuntimeHintsAgentTests {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static class PrivateClass {
|
||||||
|
|
||||||
|
private String greet() {
|
||||||
|
return "hello";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -337,13 +337,21 @@ public abstract class InstrumentedBridgeMethods {
|
||||||
|
|
||||||
public static Object methodinvoke(Method method, Object object, Object... arguments) throws InvocationTargetException, IllegalAccessException {
|
public static Object methodinvoke(Method method, Object object, Object... arguments) throws InvocationTargetException, IllegalAccessException {
|
||||||
Object result = null;
|
Object result = null;
|
||||||
|
boolean accessibilityChanged = false;
|
||||||
try {
|
try {
|
||||||
|
if (!Modifier.isPublic(method.getModifiers())) {
|
||||||
|
method.setAccessible(true);
|
||||||
|
accessibilityChanged = true;
|
||||||
|
}
|
||||||
result = method.invoke(object, arguments);
|
result = method.invoke(object, arguments);
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
RecordedInvocation invocation = RecordedInvocation.of(InstrumentedMethod.METHOD_INVOKE)
|
RecordedInvocation invocation = RecordedInvocation.of(InstrumentedMethod.METHOD_INVOKE)
|
||||||
.onInstance(method).withArguments(object, arguments).returnValue(result).build();
|
.onInstance(method).withArguments(object, arguments).returnValue(result).build();
|
||||||
RecordedInvocationsPublisher.publish(invocation);
|
RecordedInvocationsPublisher.publish(invocation);
|
||||||
|
if (accessibilityChanged) {
|
||||||
|
method.setAccessible(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue