I am using ASM 5.2 for an example project and I want to compile the project which has as dependacy the ASM library.
The java file i am trying to compile is the following:
import java.io.FileInputStream;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.MethodVisitor;
import static org.objectweb.asm.Opcodes.ASM5;
public class Parser2 {
public static void main(final String args[]) throws Exception {
FileInputStream inputFile = new FileInputStream("/src/Test.class");
ClassReader reader = new ClassReader(inputFile);
GraphClass gc = new GraphClass();
reader.accept(gc, 0);
}
}
class GraphClass extends ClassVisitor {
public GraphClass() {
super(ASM5);
}
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
GraphMethod newVisitor = new GraphMethod(name);
return newVisitor;
//return super.visitMethod(access, name, desc, signature,exceptions);
}
}
class GraphMethod extends MethodVisitor{
public String MthName;
public GraphMethod(String name) {
super(ASM5);
MthName = name;
}
public void visitMethodInsn(int opcode, java.lang.String owner, java.lang.String name, java.lang.String descriptor, boolean isInterface) {
System.out.println(owner + "." + MthName + " ===> " + owner + "." + name);
}
}
I compile it with
javac -classpath asm-all-5.2.jar Parser2.java
which creates the class files GraphClass.class, GraphMethod.class and Parser2.class.
Then upon executing the Parser2 the following error comes up.
$ java Parser2
Error: A JNI error has occurred, please check your installation and try again
Exception in thread "main" java.lang.NoClassDefFoundError: org/objectweb/asm/ClassVisitor
at java.lang.Class.getDeclaredMethods0(Native Method)
at java.lang.Class.privateGetDeclaredMethods(Class.java:2701)
at java.lang.Class.privateGetMethodRecursive(Class.java:3048)
at java.lang.Class.getMethod0(Class.java:3018)
at java.lang.Class.getMethod(Class.java:1784)
at sun.launcher.LauncherHelper.validateMainClass(LauncherHelper.java:544)
at sun.launcher.LauncherHelper.checkAndLoadMain(LauncherHelper.java:526)
Caused by: java.lang.ClassNotFoundException: org.objectweb.asm.ClassVisitor
at java.net.URLClassLoader.findClass(URLClassLoader.java:382)
at java.lang.ClassLoader.loadClass(ClassLoader.java:418)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:352)
at java.lang.ClassLoader.loadClass(ClassLoader.java:351)
... 7 more
Why does it say it cannot find the ClassVisitor?
java version in use openjdk version "1.8.0_252"
Based on this tutorial I try to get a java agent to work.
https://www.baeldung.com/java-instrumentation#loading-a-java-agent
I do get [Agent] Transforming class TestApplication
I have no errors, but I can't see any effect of transforming the class.
Eventually I would like to get both static load and dynamic load to work, but for now I focus on the static way.
public class Static_Agent {
public static void premain(String agentArgs, Instrumentation inst) {
String[] tokens = agentArgs.split(";");
String className = tokens[0];
String methodName = tokens[1];
System.out.println(">> "+className);
System.out.println(">> "+methodName);
transformClass(className, methodName, inst);
}
public static void transformClass(String className, String methodName, Instrumentation instrumentation) {
Class<?> targetCls = null;
ClassLoader targetClassLoader = null;
// see if we can get the class using forName
try {
targetCls = Class.forName(className);
targetClassLoader = targetCls.getClassLoader();
transform(targetCls, methodName, targetClassLoader, instrumentation);
return;
} catch (Exception ex) {
ex.printStackTrace();
}
// otherwise iterate all loaded classes and find what we want
for(Class<?> clazz: instrumentation.getAllLoadedClasses()) {
if(clazz.getName().equals(className)) {
targetCls = clazz;
targetClassLoader = targetCls.getClassLoader();
transform(targetCls, methodName, targetClassLoader, instrumentation);
return;
}
}
throw new RuntimeException("Failed to find class [" + className + "]");
}
public static void transform(Class<?> clazz, String methodName, ClassLoader classLoader, Instrumentation instrumentation) {
Transformer dt = new Transformer(clazz.getName(), methodName, classLoader);
instrumentation.addTransformer(dt, true);
try {
instrumentation.retransformClasses(clazz);
} catch (Exception ex) {
throw new RuntimeException("Transform failed for class: [" + clazz.getName() + "]", ex);
}
}
}
public class Transformer implements ClassFileTransformer {
/** The internal form class name of the class to transform */
private String targetClassName;
/** The class loader of the class we want to transform */
private ClassLoader targetClassLoader;
private String targetMethodName;
public Transformer(String targetClassName, String targetMethodName, ClassLoader targetClassLoader) {
this.targetClassName = targetClassName;
this.targetClassLoader = targetClassLoader;
this.targetMethodName = targetMethodName;
}
#Override
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined,
ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
byte[] byteCode = classfileBuffer;
String finalTargetClassName = this.targetClassName.replaceAll("\\.", "/");
if (!className.equals(finalTargetClassName)) {
return byteCode;
}
if (className.equals(finalTargetClassName) && loader.equals(targetClassLoader)) {
System.out.println("[Agent] Transforming class TestApplication");
try {
ClassPool cp = ClassPool.getDefault();
CtClass cc = cp.get(targetClassName);
CtMethod m = cc.getDeclaredMethod(targetMethodName);
m.addLocalVariable("startTime", CtClass.longType);
m.insertBefore("startTime = System.currentTimeMillis();");
StringBuilder endBlock = new StringBuilder();
m.addLocalVariable("endTime", CtClass.longType);
m.addLocalVariable("opTime", CtClass.longType);
endBlock.append("endTime = System.currentTimeMillis();");
endBlock.append("opTime = (endTime-startTime)/1000;");
endBlock.append("System.out.println(\"[Application] Withdrawal operation completed in:\" + opTime + \" seconds!\");");
m.insertAfter(endBlock.toString());
byteCode = cc.toBytecode();
cc.detach();
} catch (Exception e) {
System.out.println("Exception"+e);
}
}
return byteCode;
}
}
public class TestApplication {
public static void main(String[] args) {
try {
TestApplication.run();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void run() throws Exception {
System.out.println("--- start ---");
while (true) {
test();
Thread.sleep(4_000);
}
}
static int count = 0;
public static void test() {
System.out.println(count++);
}
}
I launch with:
java -javaagent:static_agent.jar="doeke.application.TestApplication;test" -jar application.jar
In case it helps, the project is here:
https://github.com/clankill3r/java_agent
Edit:
In the Transformer.java near the end of the file I use e.printStackTrace(); now.
I get the following error:
[Agent] Transforming class TestApplication
javassist.NotFoundException: doeke.application.TestApplication at
javassist.ClassPool.get(ClassPool.java:436) at
doeke.transformer.Transformer.transform(Transformer.java:48) at
java.instrument/java.lang.instrument.ClassFileTransformer.transform(ClassFileTransformer.java:246)
at
java.instrument/sun.instrument.TransformerManager.transform(TransformerManager.java:188)
at
java.instrument/sun.instrument.InstrumentationImpl.transform(InstrumentationImpl.java:563)
at
java.instrument/sun.instrument.InstrumentationImpl.retransformClasses0(Native
Method) at
java.instrument/sun.instrument.InstrumentationImpl.retransformClasses(InstrumentationImpl.java:167)
at doeke.static_agent.Static_Agent.transform(Static_Agent.java:56)
at
doeke.static_agent.Static_Agent.transformClass(Static_Agent.java:34)
at doeke.static_agent.Static_Agent.premain(Static_Agent.java:22) at
java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native
Method) at
java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at
java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566) at
java.instrument/sun.instrument.InstrumentationImpl.loadClassAndStartAgent(InstrumentationImpl.java:513)
at
java.instrument/sun.instrument.InstrumentationImpl.loadClassAndCallPremain(InstrumentationImpl.java:525)
--- start ---
0
1
Thanks for raising this question to let me have chance to take a look of Java Instrumentation.
After spending some time to cross check your sample codes and the provided tutorial. The problem is not from the programming codes, but the way how to launch your program.
If you add some loggers to the transform() method in Transformer.java, you will find that the code path is broken after running:
ClassPool cp = ClassPool.getDefault();
And, after replacing the exception catching code in the same method from:
} catch (Exception e) {
to:
} catch (NotFoundException | CannotCompileException | IOException e) {
It would give your more hints as below:
Exception in thread "main" java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at sun.instrument.InstrumentationImpl.loadClassAndStartAgent(Unknown Source)
at sun.instrument.InstrumentationImpl.loadClassAndCallPremain(Unknown Source)
Caused by: java.lang.NoClassDefFoundError: javassist/NotFoundException
at doeke.static_agent.Static_Agent.transform(Static_Agent.java:60)
at doeke.static_agent.Static_Agent.transformClass(Static_Agent.java:40)
at doeke.static_agent.Static_Agent.premain(Static_Agent.java:28)
... 6 more
Caused by: java.lang.ClassNotFoundException: javassist.NotFoundException
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)
... 9 more
FATAL ERROR in native method: processing of -javaagent failed
Up to this point, the root cause is more apparent. It is because while launching the program, those javassist relevant classes (e.g. ClassPool, CtClass, CtMethod, etc.) cannot refer to its corresponding libraries during the runtime.
So, the solution is:
assuming you have exported the static_agent.jar in the same "build" folder as of application.jar
all other folder structure remain the same as shown in your provided github
let's "cd" to the build folder in the command console
revising the original program launching script as below
Windows OS:
java -javaagent:static_agent.jar="doeke.application.TestApplication;test" -cp ../libs/javassist-3.12.1.GA.jar;application.jar doeke.application.TestApplication
Unix/Linux OS:
java -javaagent:static_agent.jar="doeke.application.TestApplication;test" -cp ../libs/javassist-3.12.1.GA.jar:application.jar doeke.application.TestApplication
You would finally get your expected result:
[Agent] In premain method.
>> doeke.application.TestApplication
>> test
[Agent] Transforming class
--- start ---
0
[Application] Withdrawal operation completed in:0 seconds!
1
[Application] Withdrawal operation completed in:0 seconds!
EDIT
In addition, let me paste some codes regarding how to insert codes in the middle of a method through javassist.
In case the test() method in TestApplication.java is changed as:
line 30 public static void test() {
line 31 System.out.println(count++);
line 32
line 33 System.out.println("Last line of test() method");
line 34 }
Assume that we want to add a line between the count and the =========, let's say "This is line separator", which the result would look like:
1
-- This is line separator --
Last line of test() method
Then, in the transform(...) method of Transformer.java, you could add a code line as of below:
m.insertAt(32,"System.out.println(\"-- This is line separator --\");");
which makes it becomes:
#Override
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined,
ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
byte[] byteCode = classfileBuffer;
String finalTargetClassName = this.targetClassName.replaceAll("\\.", "/");
if (!className.equals(finalTargetClassName)) {
return byteCode;
}
if (className.equals(finalTargetClassName) && loader.equals(targetClassLoader)) {
System.out.println("[Agent] Transforming class TestApplication");
try {
// Step 1 Preparation
ClassPool cp = ClassPool.getDefault();
CtClass cc = cp.get(targetClassName);
CtMethod m = cc.getDeclaredMethod(targetMethodName);
// Step 2 Declare variables
m.addLocalVariable("startTime", CtClass.longType);
m.addLocalVariable("endTime", CtClass.longType);
m.addLocalVariable("opTime", CtClass.longType);
// Step 3 Insertion of extra logics/implementation
m.insertBefore("startTime = System.currentTimeMillis();");
m.insertAt(32,"System.out.println(\"-- This is line separator --\");");
StringBuilder endBlock = new StringBuilder();
endBlock.append("endTime = System.currentTimeMillis();");
endBlock.append("opTime = (endTime-startTime)/1000;");
endBlock.append("System.out.println(\"[Application] Withdrawal operation completed in:\" + opTime + \" seconds!\");");
m.insertAfter(endBlock.toString());
// Step 4 Detach from ClassPool and clean up stuff
byteCode = cc.toBytecode();
cc.detach();
} catch (NotFoundException | CannotCompileException | IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
return byteCode;
}
Finally, would get result like below of printing the code in the middle of a method:
[Agent] In premain method.
className=doeke.application.TestApplication
methodName=test
>> doeke.application.TestApplication
>> test
[Agent] Transforming class TestApplication
--- start ---
0
-- This is line separator --
=========
[Application] Withdrawal operation completed in:0 seconds!
1
-- This is line separator --
=========
[Application] Withdrawal operation completed in:0 seconds!
2
-- This is line separator --
=========
[Application] Withdrawal operation completed in:0 seconds!
First of all, I am new to JSM.
I am trying to create a pool of connection for JMS ActiveMQ
Using the connection factory ActiveMQConnectionFactory I succeed to send/receive messages, but using the PooledConnectionFactoryBean it failed with this error:
Exception in thread "Thread-0" java.lang.NoClassDefFoundError: org/springframework/beans/factory/FactoryBean
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:791)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
at java.net.URLClassLoader.defineClass(URLClassLoader.java:449)
at java.net.URLClassLoader.access$100(URLClassLoader.java:71)
at java.net.URLClassLoader$1.run(URLClassLoader.java:361)
at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
at java.lang.ClassLoader.loadClass(ClassLoader.java:423)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
at java.lang.ClassLoader.loadClass(ClassLoader.java:356)
at jmxproducer.JMXProducerTest.run(JMXProducerTest.java:28)
at java.lang.Thread.run(Thread.java:722)
Caused by: java.lang.ClassNotFoundException: org.springframework.beans.factory.FactoryBean
at java.net.URLClassLoader$1.run(URLClassLoader.java:366)
at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
at java.lang.ClassLoader.loadClass(ClassLoader.java:423)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
at java.lang.ClassLoader.loadClass(ClassLoader.java:356)
... 14 more
Exception in thread "Thread-1" java.lang.NoClassDefFoundError: org/apache/activemq/pool/PooledConnectionFactoryBean
at jmxproducer.JMXProducerTest.run(JMXProducerTest.java:28)
at java.lang.Thread.run(Thread.java:722)
Exception in thread "Thread-2" java.lang.NoClassDefFoundError: org/apache/activemq/pool/PooledConnectionFactoryBean
at jmxproducer.JMXProducerTest.run(JMXProducerTest.java:28)
at java.lang.Thread.run(Thread.java:722)
Exception in thread "Thread-3" java.lang.NoClassDefFoundError: org/apache/activemq/pool/PooledConnectionFactoryBean
at jmxproducer.JMXProducerTest.run(JMXProducerTest.java:28)
at java
.lang.Thread.run(Thread.java:722)
Here is the source code:
package jmxproducer;
import javax.jms.*;
import org.apache.activemq.ActiveMQConnectionFactory;
import org.apache.activemq.pool.PooledConnectionFactoryBean;
public class JMXProducerTest implements Runnable {
private String message;
public JMXProducerTest(String message) {
this.message = message;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
#Override
public void run() {
try {
ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://localhost:61616");
PooledConnectionFactoryBean pool = new PooledConnectionFactoryBean();
pool.setConnectionFactory(connectionFactory);
// Create a Connection
Connection connection = connectionFactory.createConnection();
connection.start();
// Create a Session
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
// Create the destination (Topic or Queue)
Destination destination = session.createQueue("MY.QUEUE");
// Create a MessageProducer from the Session to the Topic or Queue
MessageProducer producer = session.createProducer(destination);
producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
// Create a messages
TextMessage msg = session.createTextMessage(message);
producer.send(msg);
session.close();
connection.close();
} catch (JMSException e) {
e.printStackTrace();
}
}
}
What did I miss? I added to the classpath this jar: activemq-all-5.8.0.jar
Thanks,
kdureidy
Did you add the Spring libraries to your project?
The error
java.lang.ClassNotFoundException: org.springframework.beans.factory.FactoryBean
seems to indicate that spring-beans-X.jar is missing from your project (where X is the version of Spring that you're missing).
I wan't to try to load a class and if this class can't be loaded to continue my program.
protected void checkClass(){
classChecked = false;
try {
ClassLoader cl = Thread.currentThread().getContextClassLoader();
Class<?> compiledClass = cl.loadClass(sTestclass); // << EXCEPTIOn lINE
cRun = compiledClass;
classChecked = true;
} catch (Exception e) {
e.printStackTrace();
System.err.println("- Testclass not found!");
System.err.println("- Make sure you typed the package name\n and the Class name correctly!");
}
}
But instead the whole progam exits with this:
Exception in thread "main" java.lang.NoClassDefFoundError: data/testcases/comman
do/ctest (wrong name: data/testcases/commando/CTest)
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClassCond(ClassLoader.java:631)
at java.lang.ClassLoader.defineClass(ClassLoader.java:615)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:14
1)
at java.net.URLClassLoader.defineClass(URLClassLoader.java:283)
at java.net.URLClassLoader.access$000(URLClassLoader.java:58)
at java.net.URLClassLoader$1.run(URLClassLoader.java:197)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
at cmd.TwCmd.checkClass(TwCmd.java:214)
at cmd.TwCmd.askForTestcase(TwCmd.java:107)
at cmd.TwCmd.anotherTestcase(TwCmd.java:146)
at cmd.TwCmd.executeInteractiveTw(TwCmd.java:85)
at cmd.TwCmd.runThrough(TwCmd.java:60)
at cmd.TwCmd.main(TwCmd.java:260)
I already surrounded it with Try/Catch but still the whole program exits on this error?
NoClassDefFoundError is not an Exception, it derives from Error.
Try catching Throwable if you want to catch them all.
You see an Error, not an Exception. Catch the NoClassDefFoundError and you should be able handle it in a catch block and continue.
(java.lang.NoClassDefFoundError is not a subclass of java.lang.Exception)
I am trying to read a N-Triples (.nt) DBpedia file with NxParser, but I had the following error, and I don't know what to do.
Exception in thread "main" java.lang.NoClassDefFoundError: org/semanticweb/yars/nx/parser/NxParser$1
at org.semanticweb.yars.nx.parser.NxParser.stringItFromBufferedReader(Unknown Source)
at org.semanticweb.yars.nx.parser.NxParser.<init>(Unknown Source)
at org.semanticweb.yars.nx.parser.NxParser.<init>(Unknown Source)
at SentencesMatching_prova.main(SentencesMatching_prova.java:29)
Caused by: java.lang.ClassNotFoundException: org.semanticweb.yars.nx.parser.NxParser$1
at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
at java.lang.ClassLoader.loadClass(ClassLoader.java:307)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
at java.lang.ClassLoader.loadClass(ClassLoader.java:248)
... 4 more
The source code of the script is:
import java.io.*;
import org.semanticweb.yars.nx.parser.*;
public class SentencesMatching_prova {
public static void main(String[] args) {
try {
String relationFileName = "../zzz-trash/revisions_en.nt";
FileInputStream is = new FileInputStream(relationFileName);
NxParser nxp = new NxParser(is);
while (nxp.hasNext()) {
// do stuff
}
} catch (Exception ex) {
ex.printStackTrace(System.out);
}
}
}