3

I am trying to develop a script in Java which finds all .jar files in a specified directory, then them to classpath and under certain conditions, invokes their main() method. Here is my Java info:

java version "1.6.0_24"
OpenJDK Runtime Environment (IcedTea6 1.11.5) (6b24-1.11.5-0ubuntu1~12.04.1)
OpenJDK Server VM (build 20.0-b12, mixed mode)

Here is the ls of the current working dir:

clojure.jar 
loader.class
loader.java 

I am doing the following in order to add clojure.jar to the classpath and invoke its main method:

import java.io.File;

import java.net.URL;
import java.net.URLClassLoader;
import java.net.MalformedURLException;

import java.lang.reflect.Method;

public final class loader {

  public static void main (String[] args) {
    try {
      printClasspathString();
      System.out.println ("**********");
      URL[] classesRepo = { new File("clojure.jar").toURI ().toURL (),
                            new File(System.getProperty("user.dir")).toURI ().toURL ()};
      ClassLoader currentThreadClassLoader = Thread.currentThread().getContextClassLoader();
      URLClassLoader urlClassLoader = new URLClassLoader( classesRepo, currentThreadClassLoader);
      Thread.currentThread().setContextClassLoader(urlClassLoader);
      printClasspathString();
    } catch (Exception ex) {
      System.out.println(ex.getMessage ());
    }

    //Do I miss something here?

    String mainClassName="clojure.main";

    Class<?> mainClass = null;
    try {
      mainClass = Class.forName(mainClassName);
    }
    catch (Exception ex) {
      throw new IllegalArgumentException("class not found in your jar file " + mainClassName);
    }

    Method mainMethod = null;
    try {
      mainMethod = mainClass.getMethod("main", String[].class);
    }
    catch (Exception ex) {
      throw new IllegalArgumentException("class to launch (" + mainClassName + ") does not have a public static void main(String[]) method");
    }

    try {
      mainMethod.invoke(null, (Object) args);
    } catch (Exception ex) {
      System.out.println(ex.getMessage ());
    }

  }

  public static void printClasspathString() {
    ClassLoader applicationClassLoader = Thread.currentThread().getContextClassLoader();
    if (applicationClassLoader == null) {
      applicationClassLoader = ClassLoader.getSystemClassLoader();
    }
    URL[] urls = ((URLClassLoader)applicationClassLoader).getURLs();
    for(int i=0; i < urls.length; i++) {
      System.out.println (urls[i].getFile());
    }
  }

}

Unfortunately, the loader doesn't work as expected:

$ java -cp . loader
/home/proofit404/data/downloads/clojure-loader/
**********
/home/proofit404/data/downloads/clojure-loader/clojure.jar
/home/proofit404/data/downloads/clojure-loader/
Exception in thread "main" java.lang.IllegalArgumentException: class not found in your jar file clojure.main
    at loader.main(loader.java:37)

If I use the -cp option, though, everything works fine:

$ java -cp .:clojure.jar loader
/home/proofit404/data/downloads/clojure-loader/
/home/proofit404/data/downloads/clojure-loader/clojure.jar
**********
/home/proofit404/data/downloads/clojure-loader/clojure.jar
/home/proofit404/data/downloads/clojure-loader/
Clojure 1.4.0
user=> (System/exit 0)

So - what is it that I need to change in my code to make it work as expected?

1
  • You need a custom class loader - link. Commented Dec 24, 2012 at 19:11

2 Answers 2

1

I think the problem is that the Class.forName(String) method does not use the threads contextclassloader, but the classloader of the current class:

public static Class<?> forName(String className)
                    throws ClassNotFoundException

Returns the Class object associated with the class or interface with the given string name. Invoking this method is equivalent to:

    Class.forName(className, true, currentLoader)

where currentLoader denotes the defining class loader of the current class.

This means your URLClassLoader wont be used. Try instead to explicitly pass the classloader by using Class.forName(String,boolean, ClassLoader):

mainClass = Class.forName(mainClassName, true, urlClassLoader);
Sign up to request clarification or add additional context in comments.

Comments

0

Try this code and follow the comments given below:

import java.net.URL;
import java.io.IOException;
import java.net.URLClassLoader;
import java.net.MalformedURLException;

public class JarLoader extends URLClassLoader {
    public JarLoader(URL[] urls) {
        super(urls);
    }

    public void addFile(String path) throws MalformedURLException {
        String urlPath = "jar:file://" + path + "!/";
        addURL(new URL(urlPath));
    }

    public static void main(String args[]) {
        try {
            System.out.println("First attempt...");
            Class.forName("org.gjt.mm.mysql.Driver");
            //specify your class name above
        } catch (Exception ex) {
            System.out.println("Failed.");
        }

        try {
            URL urls[] = {};

            JarLoader cl = new JarLoader(urls);
            cl
                    .addFile("/opt/mysql-connector-java-5.0.4/mysql-connector-java-5.0.4-bin.jar");
            // give your jar file above.
            System.out.println("Second attempt...");
            cl.loadClass("org.gjt.mm.mysql.Driver");
            //specify your class name above
            System.out.println("Success!");
        } catch (Exception ex) {
            System.out.println("Failed.");
            ex.printStackTrace();
        }
    }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.