byte-buddy icon indicating copy to clipboard operation
byte-buddy copied to clipboard

How to give .class file as an advice

Open amar1019 opened this issue 3 years ago • 9 comments
trafficstars

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 ?

amar1019 avatar Aug 26 '22 07:08 amar1019

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.

raphw avatar Aug 26 '22 09:08 raphw

I tried with new Transformer.ForAdvice().include(AgentBuilder.class.getClassLoader())

It still throws the first error.

amar1019 avatar Aug 26 '22 09:08 amar1019

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.

raphw avatar Aug 26 '22 10:08 raphw

Yes i have added it. Agent and bytebuddy both are in bootclasspath

amar1019 avatar Aug 26 '22 11:08 amar1019

Can you provide a stack trace?

raphw avatar Aug 26 '22 13:08 raphw

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)

amar1019 avatar Aug 26 '22 13:08 amar1019

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.

raphw avatar Aug 26 '22 16:08 raphw

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.

amar1019 avatar Aug 27 '22 06:08 amar1019

That's strange. I'm afraid that I'd need a reproducer to help you further.

raphw avatar Aug 27 '22 06:08 raphw