2012-12-24 14 views
3

J'essaie de développer un script en Java qui trouve tous les fichiers .jar dans un répertoire spécifié, puis les à classpath et dans certaines conditions, appelle leur méthode main(). Voici mes informations Java:Ajouter un fichier .jar dans classpath avec Java

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) 

Voici le ls du répertoire de travail courant:

clojure.jar 
loader.class 
loader.java 

que je fais ce qui suit afin d'ajouter clojure.jar au classpath et invoquer sa méthode principale:

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()); 
    } 
    } 

} 

Malheureusement, le chargeur ne fonctionne pas comme prévu:

$ 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) 

Si j'utilise l'option -cp, bien que, tout fonctionne très bien:

$ 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) 

Alors - qu'est-ce que je dois changer dans mon code pour le faire fonctionner comme prévu?

+0

Vous avez besoin d'une classe personnalisée chargeur - [lien] (http://stackoverflow.com/questions/4095976/how -to-put-custom-classloader-à-utiliser). –

Répondre

1

Je pense que le problème est que la Class.forName (String) ne pas utiliser les fils contextclassloader, mais le classloader de la classe actuelle:

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. 

Cela signifie que votre URLClassLoader ne sera pas utilisé. Essayez plutôt de passer explicitement l'classloader en utilisant Class.forName (String, Boolean, ClassLoader):

mainClass = Class.forName(mainClassName, true, urlClassLoader); 
+0

Oui, cela fonctionne très bien. Merci beaucoup! – proofit404

0

Essayez ce code et suivez les commentaires ci-dessous:

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(); 
     } 
    } 
} 
Questions connexes