Search code examples
javaosgijavaagentsbyte-buddy

bytebuddy with osgi container


Trying to write a simple java agent, based on the sample on bytebuddy homepage. I got the agent working, but when I run it with OSGI run time, it throws java.lang.NoClassDefFoundError.

Any pointers ?

java.lang.ClassNotFoundException: com.foo.javaagent.TimingInterceptor cannot be found by ..

import net.bytebuddy.agent.builder.AgentBuilder;
import net.bytebuddy.implementation.MethodDelegation;
import net.bytebuddy.matcher.ElementMatchers;
import java.lang.instrument.Instrumentation;


    public class TimerAgent {
        public static void premain(String arguments,
                                   Instrumentation instrumentation) {
            new AgentBuilder.Default()
                    .type(ElementMatchers.nameEndsWith("World"))
                    .transform((builder, type, classLoader, module) ->
                            builder.method(ElementMatchers.any())
                                    .intercept(MethodDelegation.to(TimingInterceptor.class))
                    ).installOn(instrumentation);
        }
    }

import net.bytebuddy.implementation.bind.annotation.Origin;
import net.bytebuddy.implementation.bind.annotation.RuntimeType;
import net.bytebuddy.implementation.bind.annotation.SuperCall;

import java.lang.reflect.Method;
import java.util.concurrent.Callable;


public class TimingInterceptor {
    @RuntimeType
    public static Object intercept(@Origin Method method,
                                   @SuperCall Callable<?> callable) throws Exception {
        long start = System.currentTimeMillis();
        try {
            return callable.call();
        } finally {
            System.out.println(method + " took " + (System.currentTimeMillis() - start));
        }
    }
}

Solution

  • The TimingInterceptor class is referenced by your instrumented classes and must therefore be visible. OSGi isolates classes by their class loaders and does not set the system class loader as a parent where the agent is loaded. To circumvent this, you need to inject your classes into the bootstrap class loader where they are universially visible. To do so, isolate your interception logic in a seperate jar and attach this jar to the bootstrap class loader search path via the Instrumentation instance you use for installing the agent. You need to do so before installing the agent.