Search code examples
javaclassloaderemmajavassist

loading another class with javassist


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!


Solution

  • 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.");
    }