Search code examples
javabyte-buddyjavaagents

When using Advice of byte buddy, Exception of java.lang.NoClassDefFoundError is throwed


For some reason, I've been analyzing my own old jar file(unfortunately source code's been lost). I know what part I'm going to find but can't remember where it is. So decide to use byte buddy to get all the run flow of jar file. It's enough to log parameter values and return values of all methods in all classes(except library class, e.g, java.lang.*). I tried sample codes with a little modification, but straggle with just an exception:

 public static void premain(final String agentArgs,
                           final Instrumentation inst) {
    System.out.println(
            "+++Hey, look: I'm instrumenting a freshly started JVM!");
    new AgentBuilder.Default()
            .type(ElementMatchers.any())
            .transform(new MetricsTransformer())
            .with(AgentBuilder.Listener.StreamWriting.toSystemOut())
            .with(AgentBuilder.TypeStrategy.Default.REDEFINE)
            .installOn(inst);
}

private static class MetricsTransformer implements AgentBuilder.Transformer {
    @Override
    public DynamicType.Builder<?> transform(
            final DynamicType.Builder<?> builder,
            final TypeDescription typeDescription,
            final ClassLoader classLoader,
            final JavaModule module) {

        final AsmVisitorWrapper methodsVisitor =
                Advice.to(EnterAdvice.class, ExitAdviceMethods.class)
                        .on(ElementMatchers.isAnnotatedWith(CollectMetrics.class)
                                .and(ElementMatchers.isMethod()));

        final AsmVisitorWrapper constructorsVisitor =
                Advice.to(EnterAdvice.class, ExitAdviceConstructors.class)
                        .on(ElementMatchers.isAnnotatedWith(CollectMetrics.class)
                                .and(ElementMatchers.isConstructor()));

        return builder.visit(methodsVisitor).visit(constructorsVisitor);
    }

    private static class EnterAdvice {
        @Advice.OnMethodEnter
        static long enter() {
            return System.nanoTime();
        }
    }

    private static class ExitAdviceMethods {
        @Advice.OnMethodExit(onThrowable = Throwable.class)
        static void exit(@Advice.Origin final Executable executable,
                         @Advice.Enter final long startTime,
                         @Advice.Thrown final Throwable throwable) {
            final long duration = System.nanoTime() - startTime;
            System.out.println(duration);;
        }
    }

}

byte buddy's versions are 1.9.5, 1.7.11 jdk version: 1.8.0.191

and the Exception in the cmd:

    E:\>cd E:\workshop\_android_studio\BounAgent\out\artifacts\BounAgent_jar

E:\BounAgent_jar>java -javaagent:BounAgent.jar -jar untitled.jar
Exception in thread "main" java.lang.NoClassDefFoundError: net/bytebuddy/matcher
/ElementMatcher
        at java.lang.Class.getDeclaredMethods0(Native Method)
        at java.lang.Class.privateGetDeclaredMethods(Unknown Source)
        at java.lang.Class.getDeclaredMethod(Unknown Source)
        at sun.instrument.InstrumentationImpl.loadClassAndStartAgent(Unknown Sou
rce)
        at sun.instrument.InstrumentationImpl.loadClassAndCallPremain(Unknown So
urce)
Caused by: java.lang.ClassNotFoundException: net.bytebuddy.matcher.ElementMatche
r
        at java.net.URLClassLoader.findClass(Unknown Source)
        at java.lang.ClassLoader.loadClass(Unknown Source)
        at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
        at java.lang.ClassLoader.loadClass(Unknown Source)
        ... 5 more

FATAL ERROR in native method: processing of -javaagent failed

Thanks in advance.


Solution

  • According to an article I found:

    To launch your agent you must bundle the agent classes and resources in a jar, and in the jar manifest set the Agent-Class property to the name of your agent class containing the premain method. (An agent must always be bundled as a jar file, it cannot be specified in an exploded format.)

    It appears that your agent JAR file ("BounAgent.jar") does not contain all of the dependencies in the correct form. Specifically, the bytebuddy classes are not in the JAR file. That is causing the agent classes to fail to load.