web-dev-qa-db-fra.com

Un répertoire peut-il être ajouté au chemin de classe lors de l'exécution?

Afin de mieux comprendre comment les choses fonctionnent en Java, j'aimerais savoir si je peux ajouter dynamiquement, au moment de l'exécution, un répertoire au chemin de classe.

Par exemple, si je lance une . Jar en utilisant "Java -jar mycp.jar" et que je génère la propriété Java.class.path, je peut obtenir:

Java.class.path: '.:/Library/Java/Extensions:/System/Library/Java/Extensions:/usr/lib/Java'

Puis-je maintenant modifier ce chemin de classe lors de l'exécution pour ajouter un autre répertoire? (par exemple avant de faire le premier appel à une classe en utilisant un . jar situé dans ce répertoire que je veux ajouter).

34
Cedric Martin

Vous pouvez utiliser la méthode suivante:

URLClassLoader.addURL(URL url)

Mais vous devrez le faire avec réflexion car la méthode est protected:

public static void addPath(String s) throws Exception {
    File f = new File(s);
    URL u = f.toURL();
    URLClassLoader urlClassLoader = (URLClassLoader) ClassLoader.getSystemClassLoader();
    Class urlClass = URLClassLoader.class;
    Method method = urlClass.getDeclaredMethod("addURL", new Class[]{URL.class});
    method.setAccessible(true);
    method.invoke(urlClassLoader, new Object[]{u});
}

Voir le Java Trail sur Reflection . Surtout la section Inconvénients de Reflection

48
Jonathan Spooner

Mise à jour 2014: c'est le code de la réponse acceptée, par Jonathan Spooner de 2011, légèrement réécrit pour que les valideurs d'Eclipse ne créent plus d'avertissements (dépréciation, rawtypes)

//need to do add path to Classpath with reflection since the URLClassLoader.addURL(URL url) method is protected:
public static void addPath(String s) throws Exception {
    File f = new File(s);
    URI u = f.toURI();
    URLClassLoader urlClassLoader = (URLClassLoader) ClassLoader.getSystemClassLoader();
    Class<URLClassLoader> urlClass = URLClassLoader.class;
    Method method = urlClass.getDeclaredMethod("addURL", new Class[]{URL.class});
    method.setAccessible(true);
    method.invoke(urlClassLoader, new Object[]{u.toURL()});
}
24
knb

Oui, vous pouvez utiliser URLClassLoader .. voir l'exemple ici . N'utilise pas de réflexion.

-- Éditer --

Copier l'exemple du lien comme suggéré.

import javax.naming.*;
import Java.util.Hashtable;
import Java.net.URLClassLoader;
import Java.net.URL;
import Java.net.MalformedURLException;

public class ChangeLoader {

    public static void main(String[] args) throws MalformedURLException {
    if (args.length != 1) {
        System.err.println("usage: Java ChangeLoader codebase_url");
        System.exit(-1);
    }

    String url = args[0];
    ClassLoader prevCl = Thread.currentThread().getContextClassLoader();

    // Create class loader using given codebase
    // Use prevCl as parent to maintain current visibility
    ClassLoader urlCl = URLClassLoader.newInstance(new URL[]{new URL(url)}, prevCl);

        try {
        // Save class loader so that we can restore later
            Thread.currentThread().setContextClassLoader(urlCl);

        // Expect that environment properties are in
        // application resource file found at "url"
        Context ctx = new InitialContext();

        System.out.println(ctx.lookup("tutorial/report.txt"));

        // Close context when no longer needed
        ctx.close();
    } catch (NamingException e) {
        e.printStackTrace();
        } finally {
            // Restore
            Thread.currentThread().setContextClassLoader(prevCl);
        }
    }
}
12
Kashyap