Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to specify class path for java agent

I am write a Java Agent to instrument a target Method of a target Class.

I use the javassist library to do instrument.

So the java agent (let named CnAgent.class) need its dependency : javassist library to run.

The directory hierarchy is :

.
├── META-INF
│   └── MANIFEST.MF
├── com
│   └── yet
│       └── another
│           └── test
│               └── agent
│                   ├── CnAgent.class
│                   └── CnTransformer.class
└── lib
    └── javassist-3.18.2-GA.jar

and the MANIFEST.MF file content is :

Manifest-Version: 1.0
Class-Path: lib/javassist-3.18.2-GA.jar .
Agent-Class: com.yet.another.test.agent.CnAgent
Created-By: 1.8.0_11 (Oracle Corporation)
Can-Retransform-Classes: true

I create jar ball by following command:

jar cvfm CnAgent.jar META-INF/MENIFIEST.MF . lib

when I load the Agent with Attach API of JVM. the error prints :

error when transform : javassist/ClassPool
java.lang.NoClassDefFoundError: javassist/ClassPool

which means the javassist library cannot be found by agent code.

So my question is :

  1. How to set Agent library's class path letting it find the dependencies?

  2. Why the Class-Path option in MANIFEST.MF not works , does it only for jar directly ran in command line ?

Thanks your wisdom :)

like image 442
Chinaxing Avatar asked Feb 12 '23 20:02

Chinaxing


2 Answers

You can use the option -Xbootclasspath: (sets the path) or -Xbootclasspath/a: (appends the given path to the existing boot class path) (refer to doc from oracle). But, as described in the link, it is non-standard.

As an alternative, you can copy the missing jar file in the %JAVA_HOME%/jre/lib/ext directory.

like image 132
Jörg Bächtiger Avatar answered Feb 16 '23 02:02

Jörg Bächtiger


Per Guido's comment above, you should add Boot-Class-Path to your agent MANIFEST.MF.

See these java.lang.instrumentation docs (Manifest Attributes section)

In my case, I have this in Ant's build.xml:

    <manifest file="META-INF/MANIFEST.MF">
       <attribute name="Premain-Class" value="de.bodden.tamiflex.playout.Agent"/>
       <attribute name="Main-Class" value="de.bodden.tamiflex.playout.Agent"/>
       <attribute name="Can-Retransform-Classes" value="true"/>
       <attribute name="Implementation-Version" value="${tf.version}"/>
       <attribute name="Boot-Class-Path" value="guava-22.0.jar:guice-4.1.0.jar" />
   </manifest>

and then copy the guice and guava jars to the directory I run the command from e.g. java -verbose:class -javaagent:poa.jar -jar ExampleProject.jar > loaded.txt

This also lists all the classes loaded to allow you to debug what Java class loader is actually doing.

Neither option from whiskeyspider worked for my case.

like image 34
Neil Avatar answered Feb 16 '23 02:02

Neil