1172 votes

Inclure toutes les jars d'un répertoire dans le classpath Java

Existe-t-il un moyen d'inclure tous les fichiers jar d'un répertoire dans le classpath ?

J'essaie java -classpath lib/*.jar:. my.package.Program et il n'est pas capable de trouver les fichiers de classe qui sont certainement dans ces jars. Dois-je ajouter chaque fichier jar au classpath séparément ?

4 votes

Désolé, je ne l'ai jamais accepté. Cela devrait être un wiki communautaire. Je n'ai jamais utilisé une des réponses fournies. Je crois que j'ai créé un shell script qui a juste scanné le répertoire lib/ et créé le classpath à partir de l'analyse des noms de fichiers.

0 votes

Il y a une sorte de bogue dans cette nouvelle fonctionnalité Java, car elle ne fonctionne pas comme décrit. J'ai abandonné et utilisé Ant pour le contourner, comme décrit dans l'une des réponses.

1 votes

Il y a un problème avec le traitement des caractères génériques dans Windows. stackoverflow.com/questions/11607873/

1310voto

basszero Points 14539

Avec Java 6 ou une version ultérieure, l'option classpath prend en charge les caractères génériques. Notez ce qui suit :

  • Utilisez des guillemets droits ( " )
  • Utilisez * pas *.jar

Windows

java -cp "Test.jar;lib/*" my.package.MainClass

Unix

java -cp "Test.jar:lib/*" my.package.MainClass

C'est similaire à Windows, mais utilise : au lieu de ; . Si vous ne pouvez pas utiliser de caractères génériques, bash permet la syntaxe suivante (où lib est le répertoire contenant tous les fichiers d'archive Java) :

java -cp "$(printf %s: lib/*.jar)"

(Il est à noter que l'utilisation d'un classpath est incompatible avec la fonction -jar option. Voir aussi : Exécuter un fichier jar avec plusieurs bibliothèques de classpath à partir de l'invite de commande )

Comprendre les caractères génériques

De la Chemin de classe document :

Les entrées du chemin de la classe peuvent contenir le caractère générique du nom de base. * ce qui est considéré comme équivalent à la spécification d'une liste de tous les fichiers dans le répertoire avec l'extension .jar ou .JAR . Par exemple, l'entrée entrée du chemin de la classe foo/* spécifie tous les fichiers JAR dans le répertoire nommé foo. Une entrée classpath consistant simplement en * se développe en une liste de tous les fichiers jar dans le répertoire actuel.

Une entrée de chemin de classe qui contient * ne correspondra pas aux fichiers de classe. Pour correspondre à la fois aux classes et aux fichiers JAR dans un seul répertoire foo, utilisez l'une des deux méthodes suivantes foo;foo/* ou foo/*;foo . L'ordre choisi détermine si les classes et ressources en foo sont chargés avant les fichiers JAR dans foo ou vice versa.

Les sous-répertoires ne sont pas recherchés de manière récursive. Par exemple, foo/* cherche pour les fichiers JAR uniquement dans foo et non dans foo/bar , foo/baz etc.

L'ordre dans lequel les fichiers JAR d'un répertoire sont énumérés dans le chemin d'accès étendu aux classes n'est pas spécifique. dans le chemin d'accès élargi de la classe n'est pas spécifié et peut varier d'une plateforme et même d'un moment à l'autre sur la même machine. A application bien construite ne devrait pas dépendre d'un ordre particulier. ordre particulier. Si un ordre spécifique est requis, alors les fichiers JAR peuvent être énumérés explicitement dans le chemin de la classe.

L'expansion des jokers se fait en amont, avant l'invocation de la méthode principale d'un programme, plutôt qu'en aval, pendant la durée de l'exécution. d'un programme, plutôt que tardivement, pendant le processus de chargement des lui-même. Chaque élément du chemin de la classe d'entrée contenant un contenant un joker est remplacé par la séquence (éventuellement vide) d'éléments générée par l'énumération des fichiers JAR dans le répertoire nommé. Pour exemple, si le répertoire foo contient a.jar , b.jar et c.jar alors le chemin de la classe foo/* est transformé en foo/a.jar;foo/b.jar;foo/c.jar , et cette chaîne serait la valeur de la propriété système java.class.path .

Le site CLASSPATH n'est pas traitée différemment de la variable d'environnement l'adresse -classpath (ou -cp ) de la ligne de commande. C'est-à-dire que les caractères génériques sont sont honorés dans tous ces cas. Cependant, les caractères génériques des chemins de classe ne sont pas respectés dans l'option Class-Path jar-manifest en-tête.

Remarque : en raison d'un bogue connu dans java 8, les exemples Windows doivent utiliser une barre oblique inverse précédant les entrées avec un astérisque de fin : https://bugs.openjdk.java.net/browse/JDK-8131329

0 votes

Nous utilisons en fait Java 5 pour le moment. Mais c'est bon à savoir pour l'avenir, merci pour le conseil !

0 votes

Génial. Quelque chose comme ceci fonctionne pour moi : java -cp target/classes;target/lib/* de.byteconsult.Main

5 votes

Cette fonctionnalité est mal documentée et semble nécessiter la satisfaction de certaines conditions préalables peu évidentes pour fonctionner comme prévu.

278voto

davorp Points 1725

Sous Windows, cela fonctionne :

java -cp "Test.jar;lib/*" my.package.MainClass

et cela ne fonctionne pas :

java -cp "Test.jar;lib/*.jar" my.package.MainClass

Remarquez le *.jar , donc le joker * doit être utilisé seul .


Sous Linux, la méthode suivante fonctionne :

java -cp "Test.jar:lib/*" my.package.MainClass

Les séparateurs sont deux-points au lieu de points-virgules .

25 votes

La réponse parfaite. 2 choses importantes à noter : 1) Utilisez des guillemets et 2) Utilisez * seulement, pas *.jar

5 votes

Un an et 8 mois plus tard, l'édition que j'ai faite pour inclure la version UNIX m'a encore sauvé. :) C'est marrant de voir qu'il ne reconnaît pas mes fichiers jar avec des noms de domaine. *.jar mais seulement avec * .

0 votes

J'ai découvert que l'ordre des classpaths est important (mais je ne sais pas pourquoi). J'obtenais des erreurs jusqu'à ce que je change l'ordre des classpaths.

76voto

oxbow_lakes Points 70013

Nous contournons ce problème en déployant une principal fichier jar myapp.jar qui contient un manifeste ( Manifest.mf ) spécifiant un classpath avec les autres jars requis, qui sont ensuite déployés à côté. Dans ce cas, il suffit de déclarer java -jar myapp.jar lors de l'exécution du code.

Donc si vous déployez le principal jar dans un répertoire, et ensuite mettre les bocaux dépendants dans une lib Sous ce dossier, le manifeste ressemble à ceci :

Manifest-Version: 1.0
Implementation-Title: myapp
Implementation-Version: 1.0.1
Class-Path: lib/dep1.jar lib/dep2.jar

NB : ceci est indépendant de la plateforme - nous pouvons utiliser les mêmes jars pour lancer sur un serveur UNIX ou sur un PC Windows.

0 votes

Cela semble fonctionner pour un grand nombre de personnes, mais Java semble ignorer les entrées du chemin de classe dans le fichier manifeste. Nous ne pouvons pas exécuter l'application sans ajouter manuellement "lib/*" au classpath à l'aide de -cp. Avez-vous une idée ?

6 votes

La réponse d'oxbow_lakes n'est pas tout à fait correcte ; le chemin de classe est respecté (et SEUL ce chemin est respecté ; -cp/-classpath est ignoré !) si vous démarrez ce bocal avec java -jar myapp.jar. Je suppose que oxbow_lakes voulait écrire cela quand il a écrit 'java -classpath myapp.jar'.

54voto

Habi Points 259

Ma solution sur Ubuntu 10.04 utilisant java-sun 1.6.0_24 ayant toutes les jarres dans le répertoire "lib" :

java -cp .:lib/\* my.main.Class

Si cela échoue, la commande suivante devrait fonctionner (affiche tous les *.jars du répertoire lib au paramètre classpath)

java -cp $(for i in lib/\*.jar ; do echo -n $i: ; done). my.main.Class

4 votes

Une note amusante. java -cp lib/* my.main.Class échouera toujours à cause de l'expansion globale de lib/*, alors que java -cp .:lib/* my.main.Class n'échouera pas car .:lib/* n'est pas un chemin global valide. Prenez le temps de noter que

1 votes

Cela ne fonctionne pas ; linux développera le fichier . vous pouvez essayer : java -cp '.:lib/ et cela fonctionne bien (notez les guillemets simples ! Cela ne fonctionnera pas avec des guillemets doubles !) En fait, .:lib/* pourrait fonctionner si ce n'est pas un glob légitime à cause des deux-points, mais cela semble un peu douteux. J'ajouterais les guillemets. Les guillemets simples indiquent à bash de ne toucher à aucune partie du contenu.

0 votes

Il importe peu (dans ce contexte) que vous utilisiez des guillemets simples ou doubles. Vous voulez empêcher l'interpréteur de commandes de développer (globbing) le *, c'est tout. Et passez le texte "lib/*" littéralement à la JVM, pour que la VM reconnaisse ceci comme un "motif spécial" et recherche elle-même les fichiers jar.

48voto

Pops Points 10137

Réponse courte : java -classpath lib/*:. my.package.Program

Oracle fournit une documentation sur l'utilisation des caractères de remplacement dans les classpaths. ici pour Java 6 et ici pour Java 7 sous le titre de la section Comprendre les caractères génériques des chemins de classe . (Au moment où j'écris ces lignes, les deux pages contiennent les mêmes informations.) Voici un résumé des points saillants :

  • En général, pour inclure tous les JARs dans un répertoire donné, vous pouvez utiliser le caractère générique * ( pas *.jar ).

  • Le caractère générique ne correspond qu'aux JARs, pas aux fichiers de classe ; pour obtenir toutes les classes d'un répertoire, il suffit de terminer l'entrée classpath par le nom du répertoire.

  • Les deux options ci-dessus peuvent être combinées pour inclure tous les fichiers JAR et de classe dans un répertoire, et les règles habituelles de précédence du classpath s'appliquent. Par exemple -cp /classes;/jars/*

  • Le caractère de remplacement sera pas rechercher les JARs dans les sous-répertoires.

  • Les points ci-dessus sont vrais si vous utilisez l'option CLASSPATH ou la propriété du système -cp ou -classpath drapeaux de ligne de commande. Toutefois, si vous utilisez l'option Class-Path L'en-tête du manifeste JAR (comme vous pouvez le faire avec un fichier de construction ant), les caractères génériques seront les suivants pas être honorée.

Oui, mon premier lien est le même que celui fourni dans la réponse la mieux notée (que je n'ai aucun espoir de dépasser), mais cette réponse ne fournit pas beaucoup d'explications au-delà du lien. Puisque ce genre de comportement est découragé sur Stack Overflow ces jours-ci j'ai pensé que je devais m'étendre sur le sujet.

0 votes

Mon problème était avec lib/*.jar plutôt que lib/*. Merci beaucoup, cela a réglé le problème. J'ai remarqué qu'il y a une différence entre : et ; mais cela peut être dû au fait que je teste plusieurs changements en même temps.

0 votes

Merci de souligner la différence entre * et *.jar.

0 votes

Je ne suis pas sûr de savoir pourquoi l'entrée supplémentaire du classpath pour "." a résolu mon problème, mais cela fonctionne maintenant. "." est le même répertoire que le répertoire que j'ai spécifié avec le caractère générique. Je ne vois pas pourquoi cela serait important, mais c'est le cas. Merci.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X