Why installOn API is giving an error in my code. I want to call instrumentation.retransformClasses API from another thread. or can we call instrumentation.retransformClasses API in bytebuddy. I want to insert a static field after class is loaded. If that's possible, a short example would be great!
public static void premain(String arguments, Instrumentation instrumentation) {
System.out.println("Agent for add fields ");
final ByteBuddy byteBuddy = new ByteBuddy().with(Implementation.Context.Disabled.Factory.INSTANCE);
new AgentBuilder.Default()
.with(byteBuddy).with(RedefinitionStrategy.RETRANSFORMATION)
.with(new AgentBuilder.InitializationStrategy.SelfInjection.Eager())
.with(TypeStrategy.Default.REDEFINE)
.type((ElementMatchers.nameContains("Method")))
.transform(new Transformer() {
public Builder<?> transform(Builder<?> arg0, TypeDescription arg1, ClassLoader arg2,
JavaModule arg3) {
// TODO Auto-generated method stub
return null;
}
})
.installOn(instrumentation);
Thread thread = new Thread() {
public void run() {
System.out.println("Thread Running");
try {
Thread.currentThread().sleep(10000);
Class c[] = instrumentation.getAllLoadedClasses();
for (int i = 0; i < c.length; i++) {
String clsName = c[i].getName();
System.out.println(clsName);
if (clsName.equals("com.github.shehanperera.example.Method")) {
instrumentation.retransformClasses(c[i]);
}
}
} catch (Exception e) {
e.printStackTrace();
System.out.println(e);
}
}
};
thread.start();
}
Giving exception:
Exception in thread "main" java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at sun.instrument.InstrumentationImpl.loadClassAndStartAgent(InstrumentationImpl.java:386)
at sun.instrument.InstrumentationImpl.loadClassAndCallPremain(InstrumentationImpl.java:401)
Caused by: java.lang.IllegalStateException: Could not install class file transformer
at net.bytebuddy.agent.builder.AgentBuilder$Default.installOn(AgentBuilder.java:8538)
at net.bytebuddy.agent.builder.AgentBuilder$Default$Delegator.installOn(AgentBuilder.java:10179)
at com.github.shehanperera.addfield.Agent.premain(Agent.java:39)
... 6 more
Caused by: java.lang.UnsupportedOperationException: adding retransformable transformers is not supported in this environment
at sun.instrument.InstrumentationImpl.addTransformer(InstrumentationImpl.java:88)
at net.bytebuddy.agent.builder.AgentBuilder$Default.installOn(AgentBuilder.java:8514)
... 8 more
FATAL ERROR in native method: processing of -javaagent failed
Javassist does not allow anything like that by default, javassist just does simple clever trick and allows you to edit class before it's actually loaded, as classes are loaded on first use. Otherwise typical agent with retransform must be used too.
And to create instrumentation that can retransform classes you must add proper flag to manifest:
Can-Retransform-Classes: true
https://docs.oracle.com/javase/7/docs/api/java/lang/instrument/Instrumentation.html