I am trying to write a Java Agent (for dynamic instrumentation), based off the following article: http://blog.javabenchmark.org/2013/05/java-instrumentation-tutorial.html
The problem is that I always get a ClassNotFoundException when I try to use the agent (other people who followed that article seemed to have the same problem, according to the comment section). The code for my Java agent is as follows:
Agent.java
package com.foo.tracer;
import java.lang.instrument.Instrumentation;
public class Agent {
public static void premain(String agentArgs, Instrumentation inst) {
inst.addTransformer(new MyClassFileTransformer());
}
}
MyClassTransformer.java:
package com.foo.tracer;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.security.ProtectionDomain;
import javassist.*;
public class MyClassFileTransformer implements ClassFileTransformer {
public byte[] transform(ClassLoader loader, String className, Class classBeingRedefined,
ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
byte[] byteCode = classfileBuffer;
try {
// if I remove this line, everything works
ClassPool cp = ClassPool.getDefault();
} catch (Exception ex) {
ex.printStackTrace();
}
return byteCode;
}
}
I build the project using Maven (with "mvn package"):
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.foo.tracer</groupId>
<artifactId>tracer</artifactId>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<name>tracer</name>
<url>http://maven.apache.org</url>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.4</version>
<executions>
<execution>
<phase>process-classes</phase>
<goals>
<goal>jar</goal>
</goals>
<configuration>
<archive>
<manifestEntries>
<premain-class>com.foo.tracer.Agent</premain-class>
</manifestEntries>
</archive>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.14.0-GA</version>
<type>jar</type>
</dependency>
</dependencies>
</project>
I invoke the agent as follows:
$ java -verbose:class -javaagent:PATH/tracer-1.0-SNAPSHOT.jar -jar my-app-1.0-SNAPSHOT.jar | grep -iE "(foo|javassist)"
[Loaded com.foo.tracer.Agent from file:[CUT]/tracer-1.0-SNAPSHOT.jar]
[Loaded com.foo.tracer.MyClassFileTransformer from file:[CUT]/tracer-1.0-SNAPSHOT.jar]
Exception in thread "main" java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at sun.instrument.InstrumentationImpl.loadClassAndStartAgent(InstrumentationImpl.java:386)
at sun.instrument.InstrumentationImpl.loadClassAndCallPremain(InstrumentationImpl.java:401)
Caused by: java.lang.NoClassDefFoundError: javassist/ClassPool
at com.foo.tracer.Agent.premain(Agent.java:11)
... 6 more
Caused by: java.lang.ClassNotFoundException: javassist.ClassPool
at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:338)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
... 7 more
As you can see, my own classes are loaded by the ClassLoader, but for some reason the .class Files in javassist.jar are not loaded (I think that javaassist.jar, which is packaged into tracer-1.0-SNAPSHOT.jar, is not processed by the ClassLoader). I guess there is something wrong with my pom.xml file. Can someone tell me how I can fix this?
Directory structure (in case this is relevant):
$ tree
.
├── pom.xml
└── src
├── javassist.jar
├── main
│ ├── java
│ │ └── com
│ │ └── foo
│ │ └── tracer
│ │ ├── Agent.java
│ │ └── MyClassFileTransformer.java
│ └── resources
│ └── javassist.jar
├── META-INF
│ └── MANIFEST.MF
└── test
└── java
└── com
└── tracer
└── AppTest.java