I am seeing Cannot resolve type description
errors from AgentBuilder.Listener.onError(...)
when installing an AgentBuilder
transformation for an Instrumentation
.
The agent code is:
public static void premain(final String agentArgs, final Instrumentation inst) {
System.out.println("from bytebuddy: agent premain");
new AgentBuilder.Default(new ByteBuddy().with(TypeValidation.DISABLED))
.disableClassFormatChanges()
.ignore(none())
.with(RedefinitionStrategy.RETRANSFORMATION)
.with(InitializationStrategy.NoOp.INSTANCE)
.with(TypeStrategy.Default.REDEFINE)
.with(new AgentBuilder.Listener() {
public void onDiscovery(final String typeName, final ClassLoader classLoader, final JavaModule module, final boolean loaded) {
log("Event::onDiscovery(" + typeName + ", " + getNameId(classLoader) + ", " + module + ", " + loaded + ")");
}
public void onTransformation(final TypeDescription typeDescription, final ClassLoader classLoader, final JavaModule module, final boolean loaded, final DynamicType dynamicType) {
log("Event::onTransformation(" + typeDescription.getName() + ", " + getNameId(classLoader) + ", " + module + ", " + loaded + ", " + dynamicType + ")");
}
public void onIgnored(final TypeDescription typeDescription, final ClassLoader classLoader, final JavaModule module, final boolean loaded) {
log("Event::onIgnored(" + typeDescription.getName() + ", " + getNameId(classLoader) + ", " + module + ", " + loaded + ")");
}
public void onError(final String typeName, final ClassLoader classLoader, final JavaModule module, final boolean loaded, final Throwable throwable) {
log("Event::onError(" + typeName + ", " + getNameId(classLoader) + ", " + module + ", " + loaded + ")", throwable);
}
public void onComplete(final String typeName, final ClassLoader classLoader, final JavaModule module, final boolean loaded) {
log("Event::onComplete(" + typeName + ", " + getNameId(classLoader) + ", " + module + ", " + loaded + ")");
}
})
.type(hasSuperType(named("com.ning.http.client.AsyncHttpClientConfig$Builder")))
.transform(new Transformer() {
public DynamicType.Builder<?> transform(final DynamicType.Builder<?> builder, final
System.out.println("from bytebuddy: transform");
TypeDescription typeDescription, final ClassLoader classLoader, final JavaModule module) {
return builder.visit(Advice.to(AHCBuilderExit.class).on(isDefaultConstructor()));
}})
.installOn(inst);
}
This is using ByteBuddy v1.10.2 with Mule 4 (jdk1.8) as the target application.
There is a similar post regarding this same issue here, but the responses have not led me to a solution.
The output shows "from bytebuddy: agent premain", but it does not show "from bytebuddy: transform". Instead, the logs show exceptions for many classes that belong in the bootstrap class loader, such as:
Event::onError(org.mule.weave.v2.el.WeaveExpressionLanguage, org.mule.runtime.module.artifact.api.classloader.MuleArtifactClassLoader@6d4b1d14, null, false)
java.lang.IllegalStateException: Cannot resolve type description for java.lang.Exception
at net.bytebuddy.pool.TypePool$Resolution$Illegal.resolve(TypePool.java:159)
at net.bytebuddy.pool.TypePool$Default$WithLazyResolution$LazyTypeDescription.delegate(TypePool.java:914)
at net.bytebuddy.description.type.TypeDescription$AbstractBase$OfSimpleType$WithDelegation.getSuperClass(TypeDescription.java:8031)
at net.bytebuddy.description.type.TypeDescription$Generic$OfNonGenericType.getSuperClass(TypeDescription.java:3619)
at net.bytebuddy.description.type.TypeDefinition$SuperClassIterator.next(TypeDefinition.java:314)
at net.bytebuddy.description.type.TypeDefinition$SuperClassIterator.next(TypeDefinition.java:281)
at net.bytebuddy.matcher.HasSuperTypeMatcher.matches(HasSuperTypeMatcher.java:53)
...
It seems that the class loader that's being queried for the type description is not providing the desired classes. Is there a way to specify an alternate ClassFileLocator
for these lookups?
The specific class loader that's resulting in the error is:
org.mule.runtime.module.artifact.api.classloader.MuleArtifactClassLoader
Interestingly, this instrumentation works as expected when using Byteman as the agent, with the following rule file:
RULE AsyncHttpClientConfig.Builder.<init>
CLASS com.ning.http.client.AsyncHttpClientConfig$Builder
METHOD <init>
AT EXIT
IF TRUE
DO
traceln("from byteman: AsyncHttpClientConfig$Builder.<init> triggered: " + getClass().getClassLoader());
ENDRULE
Any advice would be appreciated! Thank you for your help!
The stack trace shows that you are applying a super type check with Byte Buddy that you do not use with Byteman. If you substitute your hasSuperType(named(...))
matcher with just named(...)
, it might work without errors as this is where the error seems to happen. Byte Buddy needs to resolve all classes in a class hierarchy for being able to apply this matcher what seems to be impossible in your case.
Yet, that a ClassLoader
cannot resolve the class file for java.lang.Exception
seems weird; probably the class loader you are using is a custom implementation that does not delegate to the boot loader.
You can circumvent this by defining a custom LocationStrategy
in your agent that always queries the boot loader as an alternative option:
class BootFallbackLocationStrategy implements AgentBuilder.LocationStrategy {
@Override
public ClassFileLocator classFileLocator(ClassLoader classLoader, JavaModule module) {
return new ClassFileLocator.Compound(
ClassFileLocator.ForClassLoader.of(classLoader),
ClassFileLocator.ForClassLoader.ofBootLoader())
}
}
As mentioned in my comment, if you can name the type of the class loader that is failing to resolve the class file, I might be able to provide a more detailed answer.
I will add a standard implementation of such a location strategy in a future version of Byte Buddy to make working around this problem easier. The progress is tracked in this ticket: https://github.com/raphw/byte-buddy/issues/794