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.
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.