I am trying to add a advice in my application so that the onEnter and onExit gets called when a method CassandraFunctions.loadObjectByKey is invoked during execution flow. I used below code to register a advice.
protected void instrument(boolean t) {
Instrumentation instrument = null;
// Get loader initialized in premain class
try {
Class<?> c = Class.forName("my.loader.InstrumentLoader");
java.lang.reflect.Method m = c.getMethod("getInstrument");
instrument = (Instrumentation) m.invoke(null);
} catch (Exception e) {
e.printStackTrace();
}
if(instrument == null) {
return;
}
// Add an advice
String clzName = CassandraFunctionsAdvice.class.getName();
new AgentBuilder.Default()
.with(AgentBuilder.RedefinitionStrategy.RETRANSFORMATION)
.type(ElementMatchers.named("my.functions.CassandraFunctions"))
.transform(
new AgentBuilder.Transformer.ForAdvice()
.include(Class.class.getClassLoader())
.advice(ElementMatchers.named("loadObjectByKey"), clzName))
.installOn(instrument);
}
And the advice class looks like below:
public class CassandraFunctionsAdvice {
@Advice.OnMethodEnter
public static void onEnter(@Advice.Argument(0) String key) {
String debugText = "OnMethodEnter|loadObjectByKey|key=" + key;
System.out.println(debugText);
}
@Advice.OnMethodExit
public static void onExit(@Advice.Thrown Throwable throwable) {
String debugText = "OnMethodExit|loadObjectByKey";
System.out.println(debugText);
}
}
The class that is being instrumented looks like below:
public class CassandraFunctions {
public static Object loadObjectByKey(String key) {
....
return object;
}
}
The instrumented class my.functions.CassandraFunctions is loaded much before the function loadObjectByKey is called on a user request. I am not sure what is missing and why the advice is not getting invoked.
I have already answered your question on the GitHub issue:
The advice code is just a template. The private field is not visible to the code once it is inlined by Byte Buddy.
The question you need to ask yourself is: Could I copy-paste this code to the target class and would it still compile? If no, then you need to change your advice. If you want to manage shared state, you would need to move it to a class that is accessible to the class loader(s) in question and inject it into an appropriate location.