web-dev-qa-db-fra.com

Est-il possible "d'ajouter" au classpath dynamiquement en Java?

Java -classpath ../classes;../jar;. parserTester

Comment puis-je obtenir la fonctionnalité dans la commande ci-dessus par programme? Comme, est-il possible de fonctionner en tant que:

Java parserTester

et obtenir le même résultat? J'ai essayé d'utiliser URLClassLoader mais cela modifie le chemin de classe et n'y ajoute rien.

Merci!


Merci pour la réponse Milhous. Mais c’est ce que j’essaie de faire. Comment est-il possible de placer le bocal dans le classpath en premier? J'ai aussi essayé d'utiliser un chargeur de classe personnalisé :(

Cela fonctionne .. Mais désolé que je dois l'exécuter uniquement en tant que: analyseur syntaxique Java, j'aimerais savoir si une telle chose est possible ???

Il doit être tellement bcoz que j'ai parserTester.Java et .class dans un dossier séparé. Je dois conserver la structure du fichier. L'analyseur syntaxique utilise un fichier jar dans un dossier jar séparé.

22
gimbal

Vous pouvez utiliser un Java.net.URLClassLoader pour charger des classes avec n'importe quelle liste d'URL définie par le programme:

classe publique URLClassLoader étend SecureClassLoader

Ce chargeur de classes est utilisé pour charger Des classes et des ressources à partir d'un chemin de recherche D'URL faisant référence à la fois à des fichiers et à des répertoires JAR . Toute URL dont Se termine par un '/' est supposée faire référence à Un répertoire. Sinon, on suppose que l'URL Fait référence à un fichier JAR dans lequel Sera ouvert selon les besoins.

Le contexte AccessControlContext du thread Qui a créé l'instance de URLClassLoader sera utilisé lors du chargement ultérieur de De classes et de Ressources.

Les classes chargées sont accordées par Par défaut et seulement par Accès aux URL spécifiées lors de la création de URLClassLoader.

Depuis: 1.2

Et un jeu de jambes sophistiqué peut l’étendre pour prendre en charge l’utilisation de chemins génériques pour récupérer des répertoires entiers de fichiers JAR (ce code contient des références à des méthodes utilitaires, mais leur implémentation devrait être évidente dans le contexte):

/**
 * Add classPath to this loader's classpath.
 * <p>
 * The classpath may contain elements that include a generic file base name.  A generic basename
 * is a filename without the extension that may begin and/or end with an asterisk.  Use of the
 * asterisk denotes a partial match. Any files with an extension of ".jar" whose base name match
 * the specified basename will be added to this class loaders classpath.  The case of the filename is ignored.
 * For example "/somedir/*abc" means all files in somedir that end with "abc.jar", "/somedir/abc*"
 * means all files that start with "abc" and end with ".jar", and "/somedir/*abc*" means all files
 * that contain "abc" and end with ".jar".
 *
 */
public void addClassPath(String cp) {
    String                              seps=File.pathSeparator;                // separators

    if(!File.pathSeparator.equals(";")) { seps+=";"; }                          // want to accept both system separator and ';'
    for(StringTokenizer st=new StringTokenizer(cp,seps,false); st.hasMoreTokens(); ) {
        String pe=st.nextToken();
        File   fe;
        String bn=null;

        if(pe.length()==0) { continue; }

        fe=new File(pe);
        if(fe.getName().indexOf('*')!=-1) {
            bn=fe.getName();
            fe=fe.getParentFile();
            }

        if(!fe.isAbsolute() && pe.charAt(0)!='/' && pe.charAt(0)!='\\') { fe=new File(rootPath,fe.getPath()); }
        try { fe=fe.getCanonicalFile(); }
        catch(IOException thr) {
            log.diagln("Skipping non-existent classpath element '"+fe+"' ("+thr+").");
            continue;
            }
        if(!GenUtil.isBlank(bn)) {
            fe=new File(fe,bn);
            }
        if(classPathElements.contains(fe.getPath())) {
            log.diagln("Skipping duplicate classpath element '"+fe+"'.");
            continue;
            }
        else {
            classPathElements.add(fe.getPath());
            }

        if(!GenUtil.isBlank(bn)) {
            addJars(fe.getParentFile(),bn);
            }
        else if(!fe.exists()) {                                                 // s/never be due getCanonicalFile() above
            log.diagln("Could not find classpath element '"+fe+"'");
            }
        else if(fe.isDirectory()) {
            addURL(createUrl(fe));
            }
        else if(fe.getName().toLowerCase().endsWith(".Zip") || fe.getName().toLowerCase().endsWith(".jar")) {
            addURL(createUrl(fe));
            }
        else {
            log.diagln("ClassPath element '"+fe+"' is not an existing directory and is not a file ending with '.Zip' or '.jar'");
            }
        }
    log.diagln("Class loader is using classpath: \""+classPath+"\".");
    }

/**
 * Adds a set of JAR files using a generic base name to this loader's classpath.  See @link:addClassPath(String) for
 * details of the generic base name.
 */
public void addJars(File dir, String nam) {
    String[]                            jars;                                   // matching jar files

    if(nam.endsWith(".jar")) { nam=nam.substring(0,(nam.length()-4)); }

    if(!dir.exists()) {
        log.diagln("Could not find directory for Class Path element '"+dir+File.separator+nam+".jar'");
        return;
        }
    if(!dir.canRead()) {
        log.error("Could not read directory for Class Path element '"+dir+File.separator+nam+".jar'");
        return;
        }

    FileSelector fs=new FileSelector(true).add("BaseName","EG",nam,true).add("Name","EW",".jar",true);
    if((jars=dir.list(fs))==null) {
        log.error("Error accessing directory for Class Path element '"+dir+File.separator+nam+".jar'");
        }
    else if(jars.length==0) {
        log.diagln("No JAR files match specification '"+new File(dir,nam)+".jar'");
        }
    else {
        log.diagln("Adding files matching specification '"+dir+File.separator+nam+".jar'");
        Arrays.sort(jars,String.CASE_INSENSITIVE_ORDER);
        for(int xa=0; xa<jars.length; xa++) { addURL(createUrl(new File(dir,jars[xa]))); }
        }
    }

private URL createUrl(File fe) {
    try {
        URL url=fe.toURI().toURL();
        log.diagln("Added URL: '"+url.toString()+"'");
        if(classPath.length()>0) { classPath+=File.pathSeparator; }
        this.classPath+=fe.getPath();
        return url;
        }
    catch(MalformedURLException thr) {
        log.diagln("Classpath element '"+fe+"' could not be used to create a valid file system URL");
        return null;
        }
    }
22
Lawrence Dol

Je suis d’accord avec les deux autres affiches, il semblerait que vous compliquiez trop une classe de test. Il n’est pas rare de voir les fichiers .Java et .class dans des dossiers séparés, tout en dépendant de fichiers jar un troisième, sans modifier le chemin de classe par programme. Si vous le faites parce que vous ne voulez pas avoir à taper le chemin de classe sur la ligne de commande à chaque fois, je suggérerais un script shell ou un fichier de commandes. Mieux encore, un IDE. La question que j’ai vraiment, c’est pourquoi essayez-vous de gérer le classpath en code?

1
Jim Barrows

Vous pouvez écrire un fichier de commandes ou un fichier de script shell pour exporter le chemin d'accès aux classes et exécuter le programme Java. Sous Windows,

set classpath =% classpath%; ../ classes; ../ jars /* analyseur Java 

Sous Unix, Export classpath =% classpath%: ../ classes: ../ jars /* Java ParserTester

Si vous nommez le nom de fichier comme parser.bat ou parser.sh, vous pouvez simplement l'exécuter en appelant l'analyseur dans le système d'exploitation correspondant.

À partir de Java 1.6, vous pouvez inclure tous les fichiers jars d’un répertoire dans le chemin de classe en disant simplement/*

Si vous essayez de générer un fichier Java de manière dynamique, de le compiler et de l'ajouter dans le chemin de classe, définissez au préalable le répertoire dans lequel le fichier de classe est généré dans le chemin de classe. Si vous modifiez la classe Java déjà générée, recompilez-la après modification et si vous souhaitez charger la nouvelle classe, vous devez utiliser votre chargeur de classes personnalisé pour éviter la mise en cache de la classe .

0
raffimd

Je pense que ce que vous voulez, c'est un "Execution Wrapper" ou un "Launcher" spécifique à la plate-forme ... ce composant est généralement utilisé pour détecter votre système d'exploitation, votre architecture et vos dépendances, puis pour effectuer des réglages avant de lancer votre application. C'est un modèle de conception de la vieille école (parler des années 80 et plus tôt), mais est encore beaucoup utilisé aujourd'hui. L'idée est que votre programme peut être indépendant du système et de l'environnement et que le lanceur se préparera et indiquera au logiciel tout ce qu'il doit savoir. De nombreux programmes open source modernes le font avec des scripts Shell et des fichiers batch, etc. Apache Tomcat par exemple. Vous pouvez tout aussi facilement créer un wrapper dans Java et le lancer avec une ligne de commande exec (veillez à ajouter "&" à la fin de votre commande exec dans * NIX pour que votre wrapper puisse quitter en laissant uniquement votre logiciel en marche. .. vous permet également de fermer la fenêtre Shell sans tuer le processus) 

0
user804965

Vous pouvez implémenter votre propre class loader , mais cette classe/jar doit être dans le chemin de classe pour pouvoir être exécutée.

essayer

Java -cp *.jar:. myClass

ou

export CLASSPATH=./lib/tool.jar:.
Java myClass

ou

Java -jar file.jar
0
Milhous