byte-buddy
byte-buddy copied to clipboard
How to give .class file as an advice
Trying to load advice classes from a certain folder. It gives java.lang.IllegalStateException: Cannot resolve type description for Advice class. Approach i followed -
private static void instrumentEvent(Instrumentation inst) throws MalformedURLException, ClassNotFoundException {
ClassLoader cl = new URLClassLoader(
new URL[]{new File("E:\\GIT\\test").toURI().toURL()});
Class cls = cl.loadClass("com.test.ProcessImplAdvice");
System.out.println(cls.getName()); //prints com.test.ProcessImplAdvice
System.out.println(cls.getClass().getClassLoader()); //prints null
new AgentBuilder.Default().ignore(ElementMatchers.nameStartsWith("net.bytebuddy."))
.with(new AgentBuilder.Listener.WithTransformationsOnly(byteBuddyLogger))
.with(AgentBuilder.InitializationStrategy.NoOp.INSTANCE)
.with(AgentBuilder.RedefinitionStrategy.RETRANSFORMATION)
.with(AgentBuilder.TypeStrategy.Default.REDEFINE)
.type(named("java.lang.ProcessImpl"))
.transform(new Transformer.ForAdvice().include(Agent.class.getClassLoader())
.advice(ElementMatchers.isConstructor()
.and(ElementMatchers.takesArgument(0, String[].class))
.and(ElementMatchers.takesArgument(1, String.class)),
"com.test.ProcessImplAdvice"))
.installOn(inst);
}
If i give the same classloader used for loading the advice in the include,
private static void instrumentEvent(Instrumentation inst) throws MalformedURLException, ClassNotFoundException {
ClassLoader classloader = new URLClassLoader(
new URL[]{new File("E:\\GIT\\test").toURI().toURL()});
Class cls = classloader.loadClass("com.test.ProcessImplAdvice");
System.out.println(cls.getName()); //prints com.test.ProcessImplAdvice
System.out.println(cls.getClass().getClassLoader()); //prints null
new AgentBuilder.Default().ignore(ElementMatchers.nameStartsWith("net.bytebuddy."))
.with(new AgentBuilder.Listener.WithTransformationsOnly(byteBuddyLogger))
.with(AgentBuilder.InitializationStrategy.NoOp.INSTANCE)
.with(AgentBuilder.RedefinitionStrategy.RETRANSFORMATION)
.with(AgentBuilder.TypeStrategy.Default.REDEFINE)
.type(named("java.lang.ProcessImpl"))
.transform(new Transformer.ForAdvice().include(classloader)
.advice(ElementMatchers.isConstructor()
.and(ElementMatchers.takesArgument(0, String[].class))
.and(ElementMatchers.takesArgument(1, String.class)),
"com.test.ProcessImplAdvice"))
.installOn(inst);
}
I get java.lang.IllegalArgumentException: No advice defined by class com.test.ProcessImplAdvice
How do i achieve this ?
I assume the Byte Buddy advice annotation types are missing from the class loader. Add the class loader that defines Byte Buddy to the transformer.
I tried with
new Transformer.ForAdvice().include(AgentBuilder.class.getClassLoader())
It still throws the first error.
In the end, Byte Buddy calls the class loader via getResourceAsStream. If either the advice class or the Byte Buddy classes are missing from the class loaders ghat are registered, you'll get this error.
Did you add your agent to the boot loader? Resources would not be visible from there.
Yes i have added it. Agent and bytebuddy both are in bootclasspath
Can you provide a stack trace?
Here is the stacktrace.
java.lang.IllegalStateException: Cannot resolve type description for com.test.ProcessImplAdvice
at net.bytebuddy.pool.TypePool$Resolution$Illegal.resolve(TypePool.java:161)
at net.bytebuddy.pool.TypePool$Default$WithLazyResolution$LazyTypeDescription.delegate(TypePool.java:1038)
at net.bytebuddy.description.type.TypeDescription$AbstractBase$OfSimpleType$WithDelegation.getDeclaredMethods(TypeDescription.java:8231)
at net.bytebuddy.asm.Advice.to(Advice.java:346)
at net.bytebuddy.asm.Advice$WithCustomMapping.to(Advice.java:11887)
at net.bytebuddy.agent.builder.AgentBuilder$Transformer$ForAdvice$Entry$ForUnifiedAdvice.resolve(AgentBuilder.java:3024)
at net.bytebuddy.agent.builder.AgentBuilder$Transformer$ForAdvice.transform(AgentBuilder.java:2810)
at net.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer.doTransform(AgentBuilder.java:10928)
at net.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer.transform(AgentBuilder.java:10866)
at net.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer.access$1700(AgentBuilder.java:10584)
at net.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer$LegacyVmDispatcher.run(AgentBuilder.java:11258)
at net.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer$LegacyVmDispatcher.run(AgentBuilder.java:11205)
at java.security.AccessController.doPrivileged(Native Method)
at net.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer.doPrivileged(AgentBuilder.java)
at net.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer.transform(AgentBuilder.java:10773)
at sun.instrument.TransformerManager.transform(TransformerManager.java:188)
at sun.instrument.InstrumentationImpl.transform(InstrumentationImpl.java:428)
You must be able to call classLoader.getResource("com/tedt/ProcessInplAdvice.class") on some class loader. If this class loader is added to the transformer, everything should work.
I tried to give the classloader using which i loaded the class. I get No Advice found. When it print classloader.getResource as u said, it is printing proper path.
That's strange. I'm afraid that I'd need a reproducer to help you further.