web-dev-qa-db-fra.com

Ajout de fichiers à Java chemin de classe à l'exécution

Est-il possible d'ajouter un fichier (pas nécessairement un fichier jar) à Java classpath au moment de l'exécution. Plus précisément, le fichier est déjà présent dans le classpath, ce que je veux, c'est si je peux ajouter un modifié copie de ce fichier dans le chemin de classe.

Merci,

62
rdsr

Vous pouvez uniquement ajouter des dossiers ou des fichiers jar à un chargeur de classe. Donc, si vous avez un fichier de classe unique, vous devez d'abord le placer dans la structure de dossiers appropriée.

Ici est un hack plutôt laid qui s'ajoute à SystemClassLoader lors de l'exécution:

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

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

La réflexion est nécessaire pour accéder à la méthode protégée addURL. Cela pourrait échouer s'il existe un SecurityManager.

41
Thilo

Essayez celui-ci pour la taille.

private static void addSoftwareLibrary(File file) throws Exception {
    Method method = URLClassLoader.class.getDeclaredMethod("addURL", new Class[]{URL.class});
    method.setAccessible(true);
    method.invoke(ClassLoader.getSystemClassLoader(), new Object[]{file.toURI().toURL()});
}

Cela modifie le chargeur de classe système pour inclure le pot de bibliothèque donné. C'est assez moche, mais ça marche.

37
Chase

La façon dont je l'ai fait est d'utiliser mon propre chargeur de classe

URLClassLoader urlClassLoader = (URLClassLoader) ClassLoader.getSystemClassLoader();
DynamicURLClassLoader dynalLoader = new DynamicURLClassLoader(urlClassLoader);

Et créez la classe suivante:

public class DynamicURLClassLoader extends URLClassLoader {

    public DynamicURLClassLoader(URLClassLoader classLoader) {
        super(classLoader.getURLs());
    }

    @Override
    public void addURL(URL url) {
        super.addURL(url);
    }
}

Fonctionne sans aucune réflexion

13
Ranjit Aneesh

Vous pouvez essayer Java.net.URLClassloader avec l'url du dossier/jar où réside votre classe mise à jour et l'utiliser à la place du chargeur de classe par défaut lors de la création d'un nouveau thread.

5
Tobias Schulte

Oui, je pense que c'est possible, mais vous devrez peut-être implémenter votre propre chargeur de classe. Je ne l'ai jamais fait, mais c'est la voie que j'examinerais probablement.

0
ssteidl

oui, vous pouvez. il devra être dans sa structure de package dans un répertoire séparé du reste de votre code compilé si vous souhaitez l'isoler. vous allez alors simplement mettre son répertoire de base à l'avant du chemin de classe sur la ligne de commande.

0
akf