0

I have an advice class that makes use of another class that's part of the agent jar, but this other class has a dependency on a class that's not present in the agent jar. This class that's not present in the agent jar is present in another jar that's on the application class loader. The agent jar is on the system class loader. So I run into NoClassDefFoundError. I have tried using Transformer.ForAdvice as suggested in this other post, but that only works for the advice class.

// In agent jar on system class loader
MyAdviceClass {
  @Advice.OnMethodEnter
  public static void onMethodEnter() {
    YetAnotherClass.doSomething(); // works fine as Transformer.ForAdvice makes use of the correct class loader while inlining this code
    AnotherClass.doSomething(); // NoClassDefFoundError happens inside this method call
  }
}

// In agent jar on system class loader
public class AnotherClass {
  public static void doSomething() {
    YetAnotherClass.doSomething();  // NoClassDefFoundError happens here because the system class loader is used to load YetAnotherClass, but that class is only present on the application class loader
  }
}

// In user jar on application class loader
public class YetAnotherClass {
  public static void doSomething() {
    // do something else
  }
}

Transform looks like this:

.transform(new AgentBuilder.Transformer
                           .ForAdvice()
                           .include(getClass().getClassLoader())
                           .advice(methodMatcher, "com.something.advice.MyAdvice.class"));

MyAdviceClass and AnotherClass are present in the agent jar. YetAnotherClass is present in user jar that's not on the system class loader, its on the application class loader. How can I solve this problem? i.e. is there a way by which I can force the use of the application class loader in AnotherClass?

Joji Jacob
  • 11
  • 2

1 Answers1

0

I assume that AnotherClass is not visible from the class being instrumented. In this case, you should not include the class in ypur agent jar but place it in a seperate jar that you append to the boot loader via Instrumentation.appendToBootSearchPath. Classes on the boot loader are universally visible and should therefore be accessible to your instrumented class.

If the injected classes reference classes of the instrumented class loader you might however need to inject classes into the class loader using a ClassInjector.

Rafael Winterhalter
  • 42,759
  • 13
  • 108
  • 192
  • Thanks. Your assumption about AnotherClass not being visible from the instrumented class is correct. But thats not the problem. Both AnotherClass and YetAnotherClass are visible from inside the inlined advice code in the instrumented class. But YetAnotherClass is not visible from inside AnotherClass and causes NoClassDefFoundError. It looks like I will need to inject YetAnotherClass into the system class loader. – Joji Jacob Dec 23 '20 at 20:03