If I declare this advice in my agent:
public static class SequenceAdvice {
@Advice.OnMethodEnter
static void enter(@Advice.This Object thiz,
@Advice.Origin Method method,
@Advice.AllArguments Object... args) {
StackWalker walker =
StackWalker.getInstance(RETAIN_CLASS_REFERENCE);
walker.forEach(sf ->
System.out.println(sf.getClassName() + "." + sf.getMethodName())
);
}
}
as javac
compiles the lambda expression into a private method (at least in OpenJDK 11):
public class SequenceAgent$SequenceAdvice {
...
private static void lambda$enter$0(java.lang.StackWalker$StackFrame);
...
}
when the agent is attached to a program and the program is executed, it causes the program to crash:
Exception in thread "main" java.lang.IllegalAccessError:
class DemoController tried to access private method
SequenceAgent$SequenceAdvice.lambda$enter$0(
Ljava/lang/StackWalker$StackFrame;)V
(DemoController and SequenceAgent$SequenceAdvice
are in unnamed module of loader 'app')
at DemoController.getDemos(DemoController.java)
at DemoMain.main(DemoMain.java:13)
Ideally I prefer not to use objects instead of lambda expressions to workaround this:
public static class SequenceAdvice {
public static Consumer<StackWalker.StackFrame> SF_CONSUMER =
new Consumer<>() {
@Override
public void accept(StackWalker.StackFrame sf) {
System.out.println(sf.getClassName() + "." + sf.getMethodName());
}
};
@Advice.OnMethodEnter
static void enter(@Advice.This Object thiz,
@Advice.Origin Method method,
@Advice.AllArguments Object... args) {
StackWalker walker = StackWalker.getInstance(RETAIN_CLASS_REFERENCE);
walker.forEach(SF_CONSUMER);
}
}
A custom permissive security policy does not seem to resolve this error:
grant {
permission java.security.AllPermission;
};
Is there a way to temporarily disable this category of security checks (e.g. "access to private method")?
You cannot use lambda expressions from an advice. The lambda expression will be a part of the advice class that is not exposed to the target class. Instead, you will need to define a utility class that defines the lambda expressions code in public methods and reference those methods as method references.
You must then either:
Instrumentation
.Injector
.This way, the references are available to the instrumented class and can be executed.