I'm trying to intercept constructors annotated with @Inject
. That worked fine in the context of a small unit test. However in the context of a DI container like Spring it fails with a ClassNotFoundException
.
I managed to narrow down on the root cause. Calling getDeclaredConstructors
on the instrumented class will trigger this exception. Interestingly enough, if we first create an instance of that class, the problem disappears.
For example:
public class InterceptConstructorTest {
@Test
public void testConstructorInterception() throws ClassNotFoundException {
ByteBuddyAgent.install();
new AgentBuilder.Default().type(nameStartsWith("test")).transform(new AgentBuilder.Transformer() {
@Override
public Builder<?> transform(Builder<?> builder, TypeDescription td) {
return builder.constructor(isAnnotatedWith(Inject.class))
.intercept(SuperMethodCall.INSTANCE.andThen(MethodDelegation.to(ConstructorInterceptor.class)));
}
}).installOnByteBuddyAgent();
// If this line is uncommented, ClassNotFoundException won't be thrown
// MyClass myClass = new MyClass("a param");
// Manually load MyClass
Class<?> myClassDefinition = getClass().getClassLoader().loadClass("test.MyClass");
// Throws NoClassDefFoundError
for(Constructor<?> constructor : myClassDefinition.getDeclaredConstructors()) {
System.out.println(constructor);
}
}
}
The stack stack trace can be found: http://pastebin.com/1zhx3fVX
class MyClass {
@Inject
public MyClass(String aParam) {
System.out.println("constructor called");
}
}
class ConstructorInterceptor {
public static void intercept() {
System.out.println("Intercepted");
}
}