I have a program, that downloads a Git repository, builds it and launches defined Main class. It works properly with ordinary projects, but when I want to launch a JavaFX project, I get strange errors like:
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 Main.main(Main.java:31)
Caused by: java.lang.RuntimeException: java.lang.ClassNotFoundException: app.UI_Main
at javafx.application.Application.launch(Application.java:260)
at app.UI_Main.main(UI_Main.java:31)
... 5 more
Caused by: java.lang.ClassNotFoundException: app.UI_Main
at java.net.URLClassLoader.findClass(URLClassLoader.java:382)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:349)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:348)
at javafx.application.Application.launch(Application.java:248)
... 6 more
My Main class is:
public class Main {
private static final String GIT_ADDRESS = "https://github.com/lerryv/CheckCheckerDesktop";
private static final String MAIN_PATH = "app/";
private static final String MAIN_CLASS = "app.UI_Main";
public static void main(String[] args) throws GitAPIException, IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Git.cloneRepository().setURI(GIT_ADDRESS).setDirectory(Paths.get("./dir/").toFile()).call();
Collection<String> result = compile(Paths.get("./dir/src/").toFile());
String command = System.getProperty("java.home") + "/../bin/javac -d dirOut -cp \".:json-simple-1.1.jar\" " + result.join(" ");
Runtime.getRuntime().exec(command);
URLClassLoader urlClassLoader = URLClassLoader.newInstance(
new URL[]{
new File("dirOut/").toURI().toURL()
}
);
Class clazz = urlClassLoader.loadClass(MAIN_CLASS);
Method main = clazz.getDeclaredMethod("main", String[].class);
assert Modifier.isStatic(main.getModifiers());
main.invoke(null, (Object) args);
}
private static Collection<String> compile(File directory) {
assert directory.isDirectory();
Collection<String> result = new Collection<>();
boolean hasFiles = false;
for (File file: directory.listFiles()) {
if (file.isDirectory()) {
result.addAll(compile(file));
} else {
if (!hasFiles) {
String path = file.getAbsolutePath();
String extension = path.substring(path.lastIndexOf(".") + 1);
if (extension.equals("java")) hasFiles = true;
}
}
}
if (hasFiles) result.add(directory.getAbsolutePath() + "/*.java");
return result;
};
}
At first I thought it cannot find the class, but when I removed the method.invoke statement, errors disappeared. Why does it happen and are there any workarounds?
Runtime.getRuntime().exec(command)
This is starting another process, so after this line is executed compilation is not yet finished, you need to wait for this process to end, and probably you should also handle output/error stream of process to check if it succeed or not.
Process compileProc = Runtime.getRuntime().exec(command);
compileProc.waitFor();
Also I don't know what are you trying to do, but remember that not everyone might have compiler available and configured java.hame property, or configured it to different java version. (like older one and your code will not compile or newer one and you code will not run)
The program opens a new thread to start the project, but it executes the next line without monitoring its completion, so the thread can be removed if it is not necessary. If necessary, you need to write a monitoring thread to monitor and schedule all threads so that it can continue to execute after it has finished its work. Tasks of the main thread.
Related
I have a basic Maven java app that I created and it depends on JeroMQ which is a full Java implemenetation of ZeroMQ. Since I also need to wrap this java app as a windows service, I chose to use Apache Commons Daemon and specifically, followed this excellent example: http://web.archive.org/web/20090228071059/http://blog.platinumsolutions.com/node/234 Here's what the Java code looks like:
package com.org.SubscriberACD;
import java.nio.charset.Charset;
import org.zeromq.ZContext;
import org.zeromq.ZMQ;
import org.zeromq.ZMQ.Socket;
/**
* JeroMQ Subscriber for Apache Commons Daemon
*
*/
public class Subscriber
{
/**
* Single static instance of the service class
*/
private static Subscriber subscriber_service = new Subscriber();
/**
* Static method called by prunsrv to start/stop
* the service. Pass the argument "start"
* to start the service, and pass "stop" to
* stop the service.
*/
public static void windowsService(String args[]) {
String cmd = "start";
if(args.length > 0) {
cmd = args[0];
}
if("start".equals(cmd)) {
subscriber_service.start();
}
else {
subscriber_service.stop();
}
}
/**
* Flag to know if this service
* instance has been stopped.
*/
private boolean stopped = false;
/**
* Start this service instance
*/
public void start() {
stopped = false;
System.out.println("My Service Started "
+ new java.util.Date());
ZContext context = new ZContext();
Socket subscriber = context.createSocket(ZMQ.SUB);
subscriber.connect("tcp://localhost:5556");
String subscription = "MySub";
subscriber.subscribe(subscription.getBytes(Charset.forName("UTF-8")));
while(!stopped) {
System.out.println("My Service Executing "
+ new java.util.Date());
String topic = subscriber.recvStr();
if (topic == null)
break;
String data = subscriber.recvStr();
assert(topic.equals(subscription));
System.out.println(data);
synchronized(this) {
try {
this.wait(60000); // wait 1 minute
}
catch(InterruptedException ie){}
}
}
subscriber.close();
context.close();
context.destroy();
System.out.println("My Service Finished "
+ new java.util.Date());
}
/**
* Stop this service instance
*/
public void stop() {
stopped = true;
synchronized(this) {
this.notify();
}
}
}
Then I created the following folder structure just like the tutorial suggested:
E:\SubscriberACD
\bin
\subscriberACD.exe
\subscriberACDw.exe
\classes
\com\org\SubscriberACD\Subscriber.class
\logs
I then navigated to the bin directory and issued the following command to install the service:
subscriberACD.exe //IS//SubscriberACD --Install=E:\SubscriberACD\bin\subscriberACD.exe --Descriptio
n="Subscriber using Apache Commons Daemon" --Jvm=c:\glassfish4\jdk7\jre
\bin\server\jvm.dll --Classpath=E:\SubscriberACD\classes --StartMode=jvm
--StartClass=com.org.SubscriberACD.Subscriber --StartMethod=windowsSer
vice --StartParams=start --StopMode=jvm --StopClass=com.org.SubscriberA
CD.Subscriber --StopMethod=windowsService --StopParams=stop --LogPath=E:\SubscriberACD\logs --StdOutput=auto --StdError=auto
The install works fine since I can see it in Windows Services. However, when I try to start it from there, I get an error saying "Windows cannot start the SubscriberACD on Local Computer".
I checked the error logs and see the following entry:
2016-04-14 14:38:40 Commons Daemon procrun stderr initialized
Exception in thread "main" ror: org/zeromq/ZContext
at com.org.SubscriberACD.Subscriber.start(Subscriber.java:57)
at com.org.SubscriberACD.Subscriber.windowsService(Subscriber.java:33)
Caused by: java.lang.ClassNotFoundException: org.zeromq.ZContext
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)
... 2 more
It's worth noting that JeroMQ is currently a jar under my Maven Dependencies. I configured it from my POM.xml file.
I think the problem might be that my service doesn't have access to the JeroMQ jar that is under my Maven Dependencies. My assumption is that the class file doesn't contain the dependencies. So what I tried was exporting my entire project as a jar and stuck that baby under E:\SubscriberACD\classes\
So my structure now looks like this:
E:\SubscriberACD
\bin
\subscriberACD.exe
\subscriberACDw.exe
\classes
\com\org\SubscriberACD\
\Subscriber.class
\Subscriber.jar
\logs
However, that didn't fix the issue. Can anyone shed some light on this?
Change your --Classpath argument to :
--Classpath=E:\SubscriberACD\classes\your-jar-filename.jar
You almost certainly have other jarfiles you'll need, so just append them to the end of the --Classpath using ; (semi-colon) delimiters...
--Classpath=E:\SubscriberACD\classes\your-jar-filename.jar;e:\other-dir\classes\some-other.jar;etc...
So I am learning Kafka currently and have attempted to duplicate the examples provided from Apache here. This is example code for the consumer and I have written it in java just as shown. When I attempt to execute the file however I run into some issues. I am able to get the file to compile but it will not run properly.
I am executing the program with the following line without the quotations, "java TestConsumer localhost:2181 group1 test 4" This passes the 4 arguments necessary in the example code. I am provided with the following error though when I execute this command.
Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/log4j/Category
at kafka.utils.VerifiableProperties.<init>(Unknown Source)
at kafka.consumer.ConsumerConfig.<init>(Unknown Source)
at TestConsumer.ConsumerProps(TestConsumer.java:69)
at TestConsumer.<init>(TestConsumer.java:31)
at TestConsumer.main(TestConsumer.java:97)
Caused by: java.lang.ClassNotFoundException: org.apache.log4j.Category
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:425)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
at java.lang.ClassLoader.loadClass(ClassLoader.java:358)
... 5 more
I have tried going in an manually replacing the arguments with the necessary values and attempting to execute that way but I am given a different issue. Below is the error message along with the code I'm using just in case I screwed something up from the example provided. If anyone can help me out I would be incredibly appreciative since I am attempting to write my own consumer to test with parsing given information, etc. Thanks
log4j:WARN No appenders could be found for logger (kafka.utils.VerifiableProperties).
log4j:WARN Please initialize the log4j system properly.
Exception in thread "main" java.lang.NoClassDefFoundError: org/I0Itec/zkclient/IZkStateListener
at kafka.javaapi.consumer.ZookeeperConsumerConnector.<init>(Unknown Source)
at kafka.javaapi.consumer.ZookeeperConsumerConnector.<init>(Unknown Source)
at kafka.consumer.Consumer$.createJavaConsumerConnector(Unknown Source)
at kafka.consumer.Consumer.createJavaConsumerConnector(Unknown Source)
at TestConsumer.<init>(TestConsumer.java:31)
at TestConsumer.main(TestConsumer.java:97)
Caused by: java.lang.ClassNotFoundException: org.I0Itec.zkclient.IZkStateListener
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)
... 6 more
/*
* Test Consumer to gather input from
* a Producer. Attempt to perform functions
* from the produced data
*/
// Kafka API
import kafka.consumer.ConsumerConfig;
import kafka.consumer.KafkaStream;
import kafka.javaapi.consumer.ConsumerConnector;
import java.util.Map;
import java.util.HashMap;
import java.util.Properties;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit;
public class TestConsumer{
private final ConsumerConnector consumer;
private final String topic;
private ExecutorService executor;
// CONSTRUCTOR
public TestConsumer(String zookeeper, String groupid, String aTopic){
consumer = kafka.consumer.Consumer.createJavaConsumerConnector(ConsumerProps(zookeeper, groupid));
this.topic = aTopic;
}
// END CONSTRUCTOR
// RUN FUNCTION
public void run(int threads){
Map<String, Integer> topicMap = new HashMap<String, Integer>();
topicMap.put(topic, new Integer(threads));
Map<String, List<KafkaStream<byte[], byte[]>>> consumerMap = consumer.createMessageStreams(topicMap);
List<KafkaStream<byte[], byte[]>> streams = consumerMap.get(topic);
executor = Executors.newFixedThreadPool(threads); // process threads
int numThread = 0; // thread counter for consumption
// consumer all messages
for(final KafkaStream stream : streams){
executor.submit(new TestConsumerRun(stream, numThread));
numThread ++;
}
}
// END RUN FUNCTION
// CREATE PROPERTIES FUNCTION
private static ConsumerConfig ConsumerProps(String zookeeper, String groupid){
Properties properties = new Properties(); // config properties file
properties.put("zookeeper.connect", zookeeper);
properties.put("group.id", groupid);
properties.put("zookeeper.session.timeout.ms", "400");
properties.put("zookeeper.sync.time.ms", "200");
properties.put("auto.commit.interval.ms", "1000");
properties.put("auto.offset.reset", "smallest");
return new ConsumerConfig(properties);
}
// END CREATE PROPERTIES FUNCTION
// SHUTDOWN FUNCTION
public void shutdown(){
if (consumer != null) consumer.shutdown();
if (executor != null) executor.shutdown();
try{
if (!executor.awaitTermination(5000, TimeUnit.MILLISECONDS)){
System.out.println("Timed out waiting for consumer threads to shut down, exiting uncleanly");
}
} catch (InterruptedException e){
System.out.println("Interrupted during shutdown, exiting uncleanly");
}
}
// END SHUTDOWN FUNCTION
// MAIN FUNCTION
public static void main(String[] args){
String zookeeper = args[0];
String groupid = args[1];
String topic = args[2];
int threads = Integer.parseInt(args[3]);
TestConsumer test = new TestConsumer(zookeeper, groupid, topic); // send information to constructor
test.run(threads); // pass threads for iteration
try{
Thread.sleep(10000);
} catch (InterruptedException ie){
}
test.shutdown(); // close program
}
// END MAIN FUNCTION
}
/*
* Test Consumer to gather input from
* a Producer. Attempt to perform functions
* from the produced data
*/
// Kafka API
import kafka.consumer.ConsumerIterator;
import kafka.consumer.KafkaStream;
public class TestConsumerRun implements Runnable{
private KafkaStream aStream;
private int aThread;
// CONSTRUCTOR
public TestConsumerRun(KafkaStream stream, int thread){
aStream = stream; // set stream from main read
aThread = thread; // set thread from main read
}
// END CONSTRUCTOR
// RUN FUNCTION
public void run(){
ConsumerIterator<byte[], byte[]> iterator = aStream.iterator(); // used to check throughout the list continiously
while(iterator.hasNext())
System.out.println("Thread " + aThread + ": " + new String(iterator.next().message()));
System.out.println("Shutting down Thread: " + aThread);
}
// END RUN FUNCTION
}
Try adding BasicConfigurator.configure(); in the main method and it will work fine.
I had the same problem. You need to add log4j jar to your classpath. Also you might need to add slf4j and commons-logging.
java.lang.NoClassDefFoundError occurs when JVM can't find the class at runtime. (But it was there during compile.) Happens when a jar is missing during runtime and also for many other reasons. Your classpath during the compile and runtime needs to be the same. Sometimes you might have the same jar with different versions, so at runtime JVM might find the different version rather than the one used in compile.
I have a Java program based on ASM 5.0.2 to extract dependency between classes. The program works fine with an ordinary Java application. However, when I run the program as a plugin then it crashes with the bug: java.lang.ClassNotFoundException.
As an example if the example class uses junit.Assert, then when I run the project as an ordinary java application, it find this dependency, but when as plugin the below error:
java.lang.ClassNotFoundException: org.junit.Assert
at java.net.URLClassLoader$1.run(URLClassLoader.java:372)
at java.net.URLClassLoader$1.run(URLClassLoader.java:361)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:360)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at java.net.FactoryURLClassLoader.loadClass(URLClassLoader.java:798)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:340)
Part of code that I think error is because of that is as below, and the whole code can be find in this link:
class ClassCollector extends Remapper {
static Set<Class<?>> getClassesUsedBy(final String name, final String prefix, File root) throws IOException {
final ClassReader reader = new ClassReader(name);
final Set<Class<?>> classes = new TreeSet<Class<?>> (new Comparator<Class<?>>() {
#Override
public int compare (final Class<?> o1, final Class<?> o2) {
return o1.getName().compareTo (o2.getName());
}
});
final Remapper remapper = new ClassCollector(classes, prefix, root);
final ClassWriter inner = new ClassWriter(ClassWriter.COMPUTE_MAXS);
final RemappingClassAdapter visitor = new RemappingClassAdapter(inner, remapper);
try {
reader.accept(visitor, ClassReader.EXPAND_FRAMES);
}
catch (Exception ex) {
ex.toString();
}
return classes;
}
Important: when I initialized inner (as below) with null, then the program does not crash, but cannot detect all dependencies, and for example cannot detect assert dependency in the above example.
final ClassVisitor inner = null; //new ClassWriter(ClassWriter.COMPUTE_MAXS);
Please let me know if any one knows why the program is correct as an ordinary java application, but crash as plugin.
ClassReader(String name) uses the ClassLoader.loadSystemResourceAsStream() method to access the bytes for a requested class. If the classes you want to analyze are not in the class path, this won't work, since the class path is what loadSystemResourceAsStream searches.
I am making a program that operates as multiple JAR file dependencies. Basically, the thing loops through the .class files in a JAR file and gets a Class object for each of them. Each JAR has a Plugin.class file that I don't want to be available, but I want all the Classes to be accessible by other JAR dependencies as well as the main program. For example, in one JAR I have the class something.somethingelse.SomeClass, and from a second one (I made sure it is loaded second) I want to be able to import (at execution because it's in a separate JARfile) something.somethingelse.SomeClass and use it. I Have tried this after loading it into a Class object but it gives me ClassNotFound errors. I am using the newest java update and the newest version of eclipse IDE. I have three projects, "main", "aaa", and "aab". I have aaa and aab exported to JARs of which the contents are loaded into Class objects by main. aaa is loaded before aab, and I want aab to be able to access the classes from aaa through import aaa.Class. How can I (from main) make the classes of both jarfiles available to each other?
Here is my load plugin function:
public static void load(File file) throws Exception
{
JarFile jarFile = new JarFile(file);
Enumeration e = jarFile.entries();
URL[] urls = new URL[] { file.toURI().toURL() };
ClassLoader cl = new URLClassLoader(urls);
while (e.hasMoreElements()) {
JarEntry je = (JarEntry) e.nextElement();
if(je.isDirectory() || !je.getName().endsWith(".class") || je.getName() == "Plugin.class"){
continue;
}
// -6 because of .class
String className = je.getName().substring(0,je.getName().length()-6);
className = className.replace('/', '.');
Class c = cl.loadClass(className);
}
ClassLoader loader = new URLClassLoader(urls);
Class c = loader.loadClass("Plugin");
Object cobj = c.newInstance();
Method[] allMethods = c.getDeclaredMethods();
Method method = null;
boolean found = false;
for (Method m : allMethods) {
String mname = m.getName();
if (mname == "startPlugin"){
method = m;
found = true;
}
}
if(found)
{
method.invoke(cobj);
}
else
{
//skip class
}
}
And then my first JAR (aaa.jar) declares a class called hlfl.ui.UserInterface.
My second JAR's Plugin class is as follows:
import hlfl.ui.*;
public class Plugin {
//THIS DEPENDENCY EXPORTS TO: aab.jar
public void startPlugin()
{
System.out.println("Plugin Loading Interface Loaded [AAB]");
UserInterface c = new UserInterface();
}
}
But when I run it it gives me the following:
java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun. reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at sf.htmlguy.hlaunch.PluginLoader.load(PluginLoader.java:58)
at sf.htmlguy.hlaunch.PluginLoader.loadAll(PluginLoader.java:22)
at sf.htmlguy.hlaunch.HLaunch.main(HLaunch.java:14)
Caused by: java.lang.NoClassDefFoundError: hlfl/ui/UserInterface
at Plugin.startPlugin(Plugin.java:7)
... 7 more
Caused by: java.lang.ClassNotFoundException: hlfl.ui.UserInterface
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:424)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
... 8 more
Just in case, the code is on SourceForge (the three projects are in subdirectories, "hlaunch for linux" is the main one.):
https://sourceforge.net/p/hlaunch/code
As far as I can tell your load method is creating a URLClassLoader containing just one JAR file. So you're going to end up with a classloader structure like this
main
/ \
/ \
UCL with aaa.jar UCL with aab.jar
thus classes in aaa and in aab can both see classes in main, but aaa and aab cannot see each other. If you want each plugin to be able to see the classes of those plugins that were loaded before it, then you need to arrange things so that each plugin you load uses the classloader of the previous plugin as its parent
main
|
UCL with aaa.jar
|
UCL with aab.jar
To do this you'd have to cache the loader you create when you load one plugin, and then pass that as a parameter when you create the next plugin's classloader.
private static ClassLoader lastPluginClassLoader = null;
public static void load(File file) throws Exception {
//...
ClassLoader loader = null;
if(lastPluginClassLoader == null) {
loader = new URLClassLoader(urls);
} else {
loader = new URLClassLoader(urls, lastPluginClassLoader);
}
lastPluginClassLoader = loader;
// ...
}
But all this (a) is not thread safe unless synchronized and (b) makes the behaviour critically dependent on the order in which the plugins are loaded. To do things properly you'd need some way to declare which plugins depend on which other plugins, and set up the classloader tree appropriately, etc. etc.
... and if you go too far down that road you've just re-invented OSGi.
I have two projects: a profiler and a basic application (with JUnit tests)
The profiler uses Javassist to instrument the basic application.
When the profiler is inside the basic application, it works fine.
When the profiler is outside the basic application, I have to import the basic application jar file into the build path on Eclipse to be abble to instrument my application.
I want to run my profiler on my basic application in command line as EMMA does:
java -jar profiler.jar run application.jar
But I don't know how to tell my profiler, ok, instrument this jar.
Here is my profiler main code:
public static void main(String[] args) throws Exception {
Loader loader = new Loader();
loader.addTranslator(ClassPool.getDefault(), new Profiler());
try {
loader.run("com.application.bookstore.test.Test", null);
} catch (Throwable e) {
e.printStackTrace();
}
}
I tried to do that:
final String arg = args[0];
final String[] commandArgs = new String[args.length - 1];
System.arraycopy(args, 1, commandArgs, 0, commandArgs.length-1);
loader.run(arg, commandArgs);
But when I run it, I get:
[kdelemme#pdkdelemme build]$ java -jar profiler.jar bookstore.jar
java.lang.ClassNotFoundException: bookstore.jar
at java.net.URLClassLoader$1.run(URLClassLoader.java:217)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:205)
at java.lang.ClassLoader.loadClass(ClassLoader.java:321)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:294)
at java.lang.ClassLoader.loadClass(ClassLoader.java:266)
at javassist.Loader.delegateToParent(Loader.java:429)
at javassist.Loader.loadClass(Loader.java:315)
at java.lang.ClassLoader.loadClass(ClassLoader.java:266)
at javassist.Loader.run(Loader.java:289)
at com.modeln.Profiler.main(Profiler.java:93)
So I tried to run directly into my Main class directory:
[kdelemme#pdkdelemme test]$ ls
profiler.jar Test.class
[kdelemme#pdkdelemme test]$ java -jar profiler.jar Test
java.lang.NoClassDefFoundError: Test (wrong name: com/application/bookstore/test/Test)
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:634)
at java.lang.ClassLoader.defineClass(ClassLoader.java:480)
at javassist.Loader.findClass(Loader.java:380)
at javassist.Loader.loadClass(Loader.java:312)
at java.lang.ClassLoader.loadClass(ClassLoader.java:266)
at javassist.Loader.run(Loader.java:289)
at com.modeln.Profiler.main(Profiler.java:93)
So Have you any ideas to how run my profiler on an outside jar project? Thanks a lot!
Ok, here's the solution: Just pool.insertClassPath()
public static void main(String[] args) throws Exception {
Loader loader = new Loader();
loader.addTranslator(ClassPool.getDefault(), new Profiler());
try {
if (args.length < 1) {
System.out.println(TOOL_USAGE);
} else {
//Initialize profiler with config/config.properties file
initializeProfiler();
final String[] commandArgs = new String[args.length - 1];
System.arraycopy(args, 1, commandArgs, 0, commandArgs.length);
//Open a jar file, unJar it into /tmp/ then add the /tmp/ classpath to the javassist laoder
File file = new File(args[0]);
JarFile jarFile = new JarFile(args[0]);
Manifest manifest = jarFile.getManifest();
String mainClassName = null;
if (manifest != null) {
mainClassName = manifest.getMainAttributes().getValue("Main-Class");
}
jarFile.close();
mainClassName = mainClassName.replaceAll("/", ".");
//Default temp directory is Jarfilename without .jar
final File workDir = File.createTempFile(args[0].substring(0, args[0].indexOf('.')), "");
workDir.delete();
workDir.mkdirs();
//Unjar all files into WorkDir temp directory
unJar(file, workDir);
//Add all directories into classPath
createClassPath(workDir, file);
//Add the classPath with unJar files into the Javassist ClassPool
ClassPool pool = ClassPool.getDefault();
pool.insertClassPath(workDir + "/");
loader.run(mainClassName, null);
}
} catch (Throwable e) {
e.printStackTrace();
}
System.out.println("Instrumentation of " + args[0] + " finished.");
}