2010-08-27 13 views
10

Je tente de charger des classes dynamiquement dans un composant. J'utilise un sélecteur de fichier pour sélectionner le fichier .JAR qui sera chargé, puis un volet d'options pour obtenir le nom de la classe.Java Dynamiquement Chargement d'une classe

Je traînants l'Internet à la recherche pour savoir comment convertir un fichier java à une URL afin de le charger dans URLClassLoader et je suis venu avec:

File myFile = filechooser.getSelectedFile(); 
String className = JOptionPane.showInputDialog(
    this, "Class Name:", "Class Name", JOptionPane.QUESTION_MESSAGE); 

URL myUrl= null; 
try { 
    myUrl = myFile.toURL(); 
} catch (MalformedURLException e) { 
} 

URLClassLoader loader = new URLClassLoader(myUrl); 
loader.loadClass(className); 

Je reçois maintenant un « ne peut pas trouver le symbole 'erreur pour le chargement de l'URL dans le URLClassLoader

+1

Est-ce que 'trahit' un mot? La seule chose que google suggère est 'trolled' :-) http://www.urbandictionary.com/define.php?term=trolled –

+0

@seanizer: "trawled" -séparé, dans le cadre d'une recherche. – trashgod

+1

@trashgod qui sonne beaucoup mieux ... –

Répondre

5

ClassPathHacker.java trouvé dans this forum thread, est une option pour charger les classes dynamiquement.

import java.lang.reflect.*; 
import java.io.*; 
import java.net.*; 


public class ClassPathHacker { 

private static final Class[] parameters = new Class[]{URL.class}; 

public static void addFile(String s) throws IOException { 
    File f = new File(s); 
    addFile(f); 
}//end method 

public static void addFile(File f) throws IOException { 
    addURL(f.toURL()); 
}//end method 


public static void addURL(URL u) throws IOException { 

    URLClassLoader sysloader = (URLClassLoader)ClassLoader.getSystemClassLoader(); 
    Class sysclass = URLClassLoader.class; 

    try { 
     Method method = sysclass.getDeclaredMethod("addURL",parameters); 
     method.setAccessible(true); 
     method.invoke(sysloader,new Object[]{ u }); 
    } catch (Throwable t) { 
     t.printStackTrace(); 
     throw new IOException("Error, could not add URL to system classloader"); 
    }//end try catch 

}//end method 

}//end class 
8

J'aime la classe ClassPathHacker mentionné dans the answer by Zellus, mais il est plein d'appels dépréciées et les mauvaises pratiques, alors voici une version réécrite qui met également en cache la Classloader et la méthode addurl:

import java.lang.reflect.Method; 
import java.net.URL; 
import java.net.URLClassLoader; 
import java.io.IOException; 
import java.io.File; 

public class ClassPathHacker{ 

    private static final Class<URLClassLoader> URLCLASSLOADER = 
     URLClassLoader.class; 
    private static final Class<?>[] PARAMS = new Class[] { URL.class }; 

    public static void addFile(final String s) throws IOException{ 
     addFile(new File(s)); 
    } 

    public static void addFile(final File f) throws IOException{ 
     addURL(f.toURI().toURL()); 
    } 

    public static void addURL(final URL u) throws IOException{ 

     final URLClassLoader urlClassLoader = getUrlClassLoader(); 

     try{ 
      final Method method = getAddUrlMethod(); 
      method.setAccessible(true); 
      method.invoke(urlClassLoader, new Object[] { u }); 
     } catch(final Exception e){ 
      throw new IOException(
       "Error, could not add URL to system classloader"); 
     } 

    } 

    private static Method getAddUrlMethod() 
     throws NoSuchMethodException{ 
     if(addUrlMethod == null){ 
      addUrlMethod = 
       URLCLASSLOADER.getDeclaredMethod("addURL", PARAMS); 
     } 
     return addUrlMethod; 
    } 

    private static URLClassLoader urlClassLoader; 
    private static Method addUrlMethod; 

    private static URLClassLoader getUrlClassLoader(){ 
     if(urlClassLoader == null){ 
      final ClassLoader sysloader = 
       ClassLoader.getSystemClassLoader(); 
      if(sysloader instanceof URLClassLoader){ 
       urlClassLoader = (URLClassLoader) sysloader; 
      } else{ 
       throw new IllegalStateException(
        "Not an UrlClassLoader: " 
        + sysloader); 
      } 
     } 
     return urlClassLoader; 
    } 

} 
+0

+ pour la ré-factorisation! – trashgod

0

Je réécris ceci dans le scala au cas où quelqu'un aurait besoin car ce n'est pas trivial à 100% :)

/* 
* Class which allows URLS to be "dynamically" added to system class loader 
*/ 
object class_path_updater { 
    val URLCLASSLOADER = classOf[URLClassLoader] 

    var urlClassLoader = getUrlClassLoader 
    var addUrlMethod = getAddUrlMethod 

    /* 
    * addFile - have to use reflection to retrieve and call class loader addURL method as it is protected 
    */ 
    def addFile(s: String) = { 
    val urlClassLoader = getUrlClassLoader 
    try { 
     val method = getAddUrlMethod 
     method.setAccessible(true) 
     val v = (new File(s)).toURI.toURL 
     invoke(urlClassLoader, method, Array[AnyRef](v)) 
     def invoke(proxy: AnyRef, m: Method, args: Array[AnyRef]) = m.invoke(proxy, args: _*) 
    } 

    } 

    private def getAddUrlMethod: Method = { 
    if (addUrlMethod == null) addUrlMethod = URLCLASSLOADER.getDeclaredMethod("addURL", classOf[URL]) 
    addUrlMethod 
    } 

    private def getUrlClassLoader: URLClassLoader = { 
    if (urlClassLoader == null) { 
     val sysLoader = ClassLoader.getSystemClassLoader 
     sysLoader match { 
     case x: URLClassLoader => urlClassLoader = sysLoader.asInstanceOf[URLClassLoader] 
     case _ => throw new IllegalStateException("Not a UrlClassLoader: " + sysLoader) 
     } 
    } 
    urlClassLoader 
    } 
}