I am writing a java agent and I faced a pretty interesting issue that happens for me when I use Byte Buddy with the following option:
net.bytebuddy.agent.builder.AgentBuilder#disableClassFormatChanges
The issue is that it doesn't matter whether I override method of super class or not in a child of superclass, the one from superclass is always invoked.
Agent:
public class Main {
public static void premain(String agentOps, Instrumentation inst) {
instrument(agentOps, inst);
}
public static void agentmain(String agentOps, Instrumentation inst) {
instrument(agentOps, inst);
}
private static void instrument(String agentOps, Instrumentation inst) {
new AgentBuilder.Default().with(new Eager())
.disableClassFormatChanges()
.type((any()))
.transform((builder, typeDescription, classLoader, module) ->
builder.method(any()).intercept(Advice.to(LoggingAdvice.class)))
.installOn(inst);
}
public static class LoggingAdvice {
@Advice.OnMethodEnter
static void enter(@Advice.Origin String method) {
}
@Advice.OnMethodExit
static void exit(@Advice.Origin String method) {
}
}
}
And classes that I use for testing:
Super:
public class Test1 {
public void test() {
System.out.println("Test 1");
}
}
Child:
public class Test2 extends Test1 {
@Override
public void test() {
System.out.println("Test 2");
}
}
Main class:
public class Main {
public static void main(String[] args) {
new Test1().test();
new Test2().test();
}
}
The result is:
Test 1
Test 1
Expected result:
Test 1
Test 2
Without an agent, everything works as expected.
I tried to play with ElementMatcher, but it didn't give successful results.
What might be the problem here?
I think issue there in your configuration.
Can you try please next one (similar to your one but without .disableClassFormatChanges()
):
private static void instrument(String agentOps, Instrumentation inst) {
new AgentBuilder.Default()
.with(new Eager())
.type((any()))
.transform((builder, typeDescription, classLoader, module) ->
builder
.method(any())
.intercept(Advice.to(LoggingAdvice.class)))
.installOn(inst);
}
to make more clear cycle you can use tracking your calls for example
@Advice.OnMethodEnter
static void enter(@Advice.Origin String method) {
System.out.println("enter");
}
@Advice.OnMethodExit
static void exit(@Advice.Origin String method) {
System.out.println("exit");
}
possible can be useful useful to track instance where method was called.