byte-buddy
byte-buddy copied to clipboard
Advice method contains asynchronization code will throw IllegalAccessError
version 1.12.19 recurrence this issue by running code below :
import java.util.Arrays;
import java.util.concurrent.CompletableFuture;
import net.bytebuddy.ByteBuddy;
import net.bytebuddy.agent.ByteBuddyAgent;
import net.bytebuddy.asm.Advice;
import net.bytebuddy.dynamic.loading.ClassReloadingStrategy;
import net.bytebuddy.matcher.ElementMatchers;
public class ByteBuddyAdviceTest {
public static class Target {
public void sayHello(String hello) {
System.out.println(hello);
}
}
public static class TargetAgent {
@Advice.OnMethodExit
public static void methodExit(@Advice.AllArguments Object[] args) {
System.err.println("方法退出, 参数:" + Arrays.toString(args));
// success
otherMethod(args);
// Exception in thread "main" java.lang.BootstrapMethodError: java.lang.IllegalAccessError: tried to access method ...
CompletableFuture.runAsync(()->{});
}
static void otherMethod(Object[] args) {
CompletableFuture.runAsync(() -> System.out.println("otherMethod"));
}
}
public static void main(String[] args) {
ByteBuddyAgent.install();
// @formatter:off
new ByteBuddy()
.redefine(Target.class)
.visit(Advice.to(TargetAgent.class).on(ElementMatchers.named("sayHello")))
.make()
.load(Target.class.getClassLoader(), ClassReloadingStrategy.fromInstalledAgent())
;
// @formatter:on
new Target().sayHello("hello byte buddy");
}
}
This is because of the lambda expression. It's compiled to a method of its own which is not visible after inlining.
You should avoid lambdas and rather create explicit classes that you need to inject into the targeted class loader using ClassInjector. Then thereafter you can instantiate the callback explicitly and provide it where you now place the lambda.