web-dev-qa-db-fra.com

Inclusion de tous les fichiers JAR dans un répertoire du chemin de classe Java

Est-il possible d'inclure tous les fichiers jar dans un répertoire du chemin d'accès aux classes?

J'essaie Java -classpath lib/*.jar:. my.package.Program et il n'est pas en mesure de trouver des fichiers de classe qui se trouvent certainement dans ces fichiers. Dois-je ajouter chaque fichier JAR au classpath séparément?

938
Chris Serra

En utilisant Java 6 ou version ultérieure, l'option classpath prend en charge les caractères génériques. Notez les points suivants:

  • Utilisez des guillemets droits (")
  • Utilisez * et non *.jar

Windows

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

Unix

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

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

Java -cp $(echo lib/*.jar | tr ' ' ':')

(Notez que l'utilisation d'un chemin d'accès aux classes est incompatible avec l'option -jar. Voir aussi: Exécuter le fichier jar avec plusieurs bibliothèques de chemins d'accès aux classes à partir de la commande Invite )

Comprendre les caractères génériques

Depuis le Classpath document:

Les entrées de chemin d'accès aux classes peuvent contenir le caractère générique de nom de base *, ce qui revient à spécifier une liste de tous les fichiers du répertoire portant l'extension .jar ou .JAR. Par exemple, l'entrée du chemin de classe foo/* spécifie tous les fichiers JAR du répertoire nommé foo. Une entrée de chemin de classe consistant simplement en * se développe en une liste de tous les fichiers jar du répertoire en cours.

Une entrée de chemin de classe contenant * ne correspondra pas aux fichiers de classe. Pour faire correspondre les classes et les fichiers JAR dans un même répertoire foo, utilisez foo;foo/* ou foo/*;foo. L'ordre choisi détermine si les classes et les ressources dans foo sont chargées avant les fichiers JAR dans foo, ou inversement.

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

L'ordre dans lequel les fichiers JAR d'un répertoire sont énumérés dans le chemin de classe développé n'est pas spécifié et peut varier d'une plateforme à l'autre et même d'un instant à l'autre sur le même ordinateur. Une application bien construite ne doit dépendre d'aucun ordre particulier. Si un ordre spécifique est requis, les fichiers JAR peuvent être énumérés explicitement dans le chemin de classe.

L'expansion des caractères génériques est effectuée tôt, avant l'invocation de la méthode principale d'un programme, plutôt que tardivement, pendant le processus de chargement de classe lui-même. Chaque élément du chemin de classe en entrée contenant un caractère générique est remplacé par la séquence d'éléments (éventuellement vide) générée en énumérant les fichiers JAR du répertoire nommé. Par exemple, si le répertoire foo contient a.jar, b.jar et c.jar, le chemin de classe foo/* est développé 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.

La variable d'environnement CLASSPATH n'est pas traitée différemment de l'option de ligne de commande -classpath (ou -cp). Autrement dit, les caractères génériques sont respectés dans tous ces cas. Toutefois, les caractères génériques du chemin de classe ne sont pas respectés dans l'en-tête Class-Path jar-manifest.

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

1083
basszero

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, le caractère générique * doit donc être utilisé seul.


Sous Linux, les travaux suivants:

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

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

217
davorp

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

Ainsi, si vous déployez le fichier jar principal dans un répertoire, puis que vous placez les fichiers JAR dépendants dans un dossier lib situé en dessous, le manifeste se présente comme suit:

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 plate-forme - nous pouvons utiliser les mêmes fichiers JAR pour les lancer sur un serveur UNIX ou sur un PC Windows.

63
oxbow_lakes

Ma solution sur Ubuntu 10.04 utilisant Java-Sun 1.6.0_24 ayant tous les fichiers JAR dans le répertoire "lib":

Java -cp.: Lib/* my.main.Class

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

Java -cp $ (pour i dans lib/*. Jar; echo -n $ i:; done). my.main.Class
44
Habi

Pour moi, cela fonctionne dans les fenêtres.

Java -cp "/lib/*;" sample

Pour linux

Java -cp "/lib/*:" sample

J'utilise Java 6

34
SANN3

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

Oracle fournit de la documentation sur l’utilisation de caractères génériques dans les chemins de classes ici pour Java 6 et ici pour Java 7 , sous le titre de la section Comprendre les caractères génériques du chemin 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 fichiers JAR dans un répertoire donné, vous pouvez utiliser le caractère générique * ( et non *.jar). .

  • Le caractère générique correspond uniquement aux fichiers JAR, pas aux fichiers de classe; pour obtenir toutes les classes d'un répertoire, il suffit de terminer l'entrée de 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. Les règles de priorité de chemin d'accès aux classes habituelles s'appliquent. Par exemple. -cp /classes;/jars/*

  • Le caractère générique ne recherchera pas les fichiers JAR dans les sous-répertoires.

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

Oui, mon premier lien est identique à celui indiqué 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. Étant donné que ce type de comportement est déconseillé sur Stack Overflow ces jours-ci , je pensais que je l'étendrais davantage.

32
Pops

Vous pouvez essayer Java -Djava.ext.dirs=jarDirectoryhttp://docs.Oracle.com/javase/6/docs/technotes/guides/extensions/spec.html

Répertoire des fichiers jar externes lors de l'exécution de Java

26
Navi

Windows:

 Java -cp file.jar;dir/* my.app.ClassName

Linux:

 Java -cp file.jar:dir/* my.app.ClassName

Rappeler:
- Windows le séparateur de chemin est ;
- Linux le séparateur de chemin est :
- Sous Windows, si l'argument cp ne contient pas d'espace blanc, les "guillemets" sont facultatifs.

25
Wender

Correct:

Java -classpath "lib/*:." my.package.Program

Incorrect:

Java -classpath "lib/a*.jar:." my.package.Program
Java -classpath "lib/a*:."     my.package.Program
Java -classpath "lib/*.jar:."  my.package.Program
Java -classpath  lib/*:.       my.package.Program
21
rvernica

Si vous devez vraiment spécifier tous les fichiers .jar de manière dynamique, vous pouvez utiliser des scripts Shell ou Apache Ant . Il existe un projet commun appelé Commons Launcher qui vous permet de spécifier votre script de démarrage en tant que fichier de construction ant (si vous voyez ce que je veux dire).

Ensuite, vous pouvez spécifier quelque chose comme:

<path id="base.class.path">
    <pathelement path="${resources.dir}"/>
    <fileset dir="${extensions.dir}" includes="*.jar" />
    <fileset dir="${lib.dir}" includes="*.jar"/>
</path>

Dans votre fichier de construction de lancement, ce qui lancera votre application avec le bon chemin de classe.

9
user7094

Si vous utilisez Java 6, vous pouvez utiliser des caractères génériques dans le chemin d'accès aux classes.

Il est maintenant possible d'utiliser des caractères génériques dans la définition du chemin de classe:

javac -cp libs/* -verbose -encoding UTF-8 src/mypackage/*.Java  -d build/classes

Réf.: http://www.rekk.de/bloggy/2008/add-all-jars-in-a-directory-to-classpath-with-Java-se-6-using-wildcards/ =

9
prakash

Veuillez noter que le développement de caractères génériques est interrompu pour Java 7 sous Windows.

Consultez ce problème de StackOverflow pour plus d'informations.

La solution de contournement consiste à mettre un point-virgule juste après le caractère générique. Java -cp "somewhere/*;"

8
Jake Toronto

À qui cela concerne,

J'ai trouvé ce comportement étrange sur Windows sous un shell MSYS/MinGW.

Works:

$ javac -cp '.;c:\Programs\COMSOL44\plugins\*' Reclaim.Java

Ne fonctionne pas:

$ javac -cp 'c:\Programs\COMSOL44\plugins\*' Reclaim.Java
javac: invalid flag: c:\Programs\COMSOL44\plugins\com.comsol.aco_1.0.0.jar
Usage: javac <options> <source files>
use -help for a list of possible options

Je suis à peu près sûr que le caractère générique n'est pas développé par le shell, car par exemple.

$ echo './*'
./*

(Essayé avec un autre programme aussi, plutôt que le echo intégré, avec le même résultat.)

Je crois que c'est javac qui essaie de l'élargir, et il se comporte différemment, qu'il y ait un point-virgule dans l'argument ou non. Premièrement, il peut être tentant d’élargir tous les arguments qui ressemblent à des chemins. Et alors seulement, il les analyserait, avec -cp prenant uniquement le jeton suivant. (Notez que com.comsol.aco_1.0.0.jar est le deuxième fichier JAR de ce répertoire.) C'est une supposition.

C'est

$ javac -version
javac 1.7.0
6
Evgeni Sergeev

Pour Windows, des guillemets sont requis et; devrait être utilisé comme séparateur. par exemple.:

Java -cp "target\\*;target\\dependency\\*" my.package.Main
4
Alexey

Short Form: Si votre main est dans un jar, vous aurez probablement besoin d'un '-jar pathTo/yourJar/YourJarsName.jar' supplémentaire explicitement déclaré pour le faire fonctionner (même si 'YourJarsName.jar' était sur le chemin de la classe) (ou , exprimé pour répondre à la question initiale qui avait été posée il y a 5 ans: vous n'avez pas besoin de redéclarer chaque pot de manière explicite, mais il semble que même avec Java6 vous ayez besoin de redéclarer votre propre pot ...)


Forme longue: (j'ai expliqué cela au point que j'espère que même les intrus à Java pourront en profiter)

Comme beaucoup ici, j'utilise Eclipse pour exporter des fichiers JAR: (Fichier-> Exporter -> 'Fichier JAR exécutable'). Eclipse (Juno) offre trois options:

opt1: "Extract required libraries into generated JAR"
opt2: "Package required libraries into generated JAR"
opt3: "Copy required libraries into a sub-folder next to the generated JAR"

En général, j'utilisais opt2 (et opt1 était définitivement en train de casser), mais le code natif de l'un des bocaux que j'utilise a découvert des ruptures avec le truc "jarinjar" bien pratique qu'Eclipse tire parti de cette option. Même après avoir réalisé que j'avais besoin de opt3, puis avoir trouvé cette entrée StackOverflow, il m'a fallu un peu de temps pour comprendre comment lancer mon environnement principal hors d'Eclipse. Voici donc ce qui a fonctionné pour moi, car il est utile pour les autres ...


Si vous avez nommé votre fichier jar: "fooBarTheJarFile.jar" et que tout est configuré pour exporter vers le répertoire: "/ theFully/competentPath/toYourChosenDir".

(Cela signifie que le champ "Destination de l'exportation" se lit comme suit: "/theFully/qualifiedPath/toYourChosenDir/fooBarTheJarFile.jar")

Une fois que vous avez terminé, vous trouverez qu'Eclipse place toutes les bibliothèques dans un dossier nommé 'fooBarTheJarFile_lib' situé dans ce répertoire d'exportation, ce qui vous donne quelque chose comme:

/theFully/qualifiedPath/toYourChosenDir/fooBarTheJarFile.jar
/theFully/qualifiedPath/toYourChosenDir/fooBarTheJarFile_lib/SomeOtherJar01.jar
/theFully/qualifiedPath/toYourChosenDir/fooBarTheJarFile_lib/SomeOtherJar02.jar
/theFully/qualifiedPath/toYourChosenDir/fooBarTheJarFile_lib/SomeOtherJar03.jar
/theFully/qualifiedPath/toYourChosenDir/fooBarTheJarFile_lib/SomeOtherJar04.jar

Vous pouvez ensuite lancer depuis n’importe où sur votre système avec:

Java -classpath "/theFully/qualifiedPath/toYourChosenDir/fooBarTheJarFile_lib/*" -jar  /theFully/qualifiedPath/toYourChosenDir/fooBarTheJarFile.jar   package.path_to.the_class_with.your_main.TheClassWithYourMain

(Pour Java Newbies: 'package.path_to.the_class_with.your_main' est le chemin indiqué dans le package que vous trouverez en haut du fichier 'TheClassWithYourMain.Java' contenant le 'main ( ] args) {...} 'que vous souhaitez exécuter en dehors de Java)


Le piège à noter est qu’avoir "fooBarTheJarFile.jar" dans la liste des fichiers jar de votre chemin de classe déclaré n’est pas suffisant. Vous devez déclarer explicitement '-jar' et redéclarer l'emplacement de ce fichier .jar.

par exemple. cela casse:

 Java -classpath "/theFully/qualifiedPath/toYourChosenDir/fooBarTheJarFile.jar;/theFully/qualifiedPath/toYourChosenDir/fooBarTheJarFile_lib/*"  somepackages.inside.yourJar.leadingToTheMain.TheClassWithYourMain

retraité avec les chemins relatifs:

cd /theFully/qualifiedPath/toYourChosenDir/;
BREAKS:  Java -cp "fooBarTheJarFile_lib/*"                                package.path_to.the_class_with.your_main.TheClassWithYourMain    
BREAKS:  Java -cp ".;fooBarTheJarFile_lib/*"                              package.path_to.the_class_with.your_main.TheClassWithYourMain   
BREAKS:  Java -cp ".;fooBarTheJarFile_lib/*"   -jar                       package.path_to.the_class_with.your_main.TheClassWithYourMain   
WORKS:   Java -cp ".;fooBarTheJarFile_lib/*"   -jar  fooBarTheJarFile.jar package.path_to.the_class_with.your_main.TheClassWithYourMain   

(avec Java version "1.6.0_27"; via un serveur OpenJDK 64 bits VM sur Ubuntu 12.04)

4
Matt S.

Toutes les solutions ci-dessus fonctionnent parfaitement si vous développez et exécutez l'application Java en dehors de tout IDE comme Eclipse ou Netbeans.

Si vous utilisez Windows 7 et utilisez Eclipse IDE pour le développement en Java, vous pouvez rencontrer des problèmes si vous utilisez Invite de commande pour exécuter les fichiers de classe intégrés à Eclipse.

Par exemple. Votre code source dans Eclipse présente la hiérarchie de packages suivante: edu.sjsu.myapp.Main.Java

Vous avez json.jar comme dépendance externe pour le fichier Main.Java

Lorsque vous essayez d'exécuter Main.Java à partir d'Eclipse, celui-ci s'exécutera sans problème.

Mais lorsque vous essayez d'exécuter cette commande à l'aide de l'invite de commandes après la compilation de Main.Java dans Eclipse, des erreurs étranges sont générées, telles que "ClassNotDef Error blah blah".

Je suppose que vous êtes dans le répertoire de travail de votre code source !!

Utilisez la syntaxe suivante pour l'exécuter à partir de la commande Invite:

  1. javac -cp ".; json.jar" Main.Java

  2. Java -cp ".; json.jar" edu.sjsu.myapp.Main

    [Ne manquez pas le. au dessus de]

En effet, vous avez placé Main.Java dans le package edu.sjsu.myapp et Java.exe recherchera le modèle exact.

J'espère que ça aide !!

4
realPK

La seule façon dont je sais comment faire est de le faire individuellement, par exemple:

setenv CLASSPATH /User/username/newfolder/jarfile.jar:jarfile2.jar:jarfile3.jar:.

J'espère que ça t'as aidé!

3
ParseTheData

classe de wepapp:

  > mvn clean install

  > Java -cp "webapp/target/webapp-1.17.0-SNAPSHOT/WEB-INF/lib/tool-jar-1.17.0-SNAPSHOT.jar;webapp/target/webapp-1.17.0-SNAPSHOT/WEB-INF/lib/*" com.xx.xx.util.EncryptorUtils param1 param2
3
Mindaugas K.

Ce n’est pas une solution directe pour pouvoir définir/* sur -cp, mais j’espère que vous pourrez utiliser le script suivant pour faciliter un peu la situation concernant les chemins de classes dynamiques et les répertoires lib.

 libDir2Scan4jars="../test";cp=""; for j in `ls ${libDir2Scan4jars}/*.jar`; do if [ "$j" != "" ]; then cp=$cp:$j; fi; done; echo $cp| cut -c2-${#cp} > .tmpCP.tmp; export tmpCLASSPATH=`cat .tmpCP.tmp`; if [ "$tmpCLASSPATH" != "" ]; then echo .; echo "classpath set, you can now use  ~>         Java -cp \$tmpCLASSPATH"; echo .; else echo .; echo "Error please check libDir2Scan4jars path"; echo .; fi; 

Scripté pour Linux, pourrait en avoir un similaire pour Windows. Si le répertoire approprié est fourni en entrée dans "libDir2Scan4jars"; le script analysera tous les fichiers jar, créera une chaîne de chemin de classe et l'exportera dans une variable env "tmpCLASSPATH".

2
Sreesankar

Définissez le chemin de classe de manière appropriée pour plusieurs fichiers JAR et les fichiers de classe du répertoire en cours.

CLASSPATH=${Oracle_HOME}/jdbc/lib/ojdbc6.jar:${Oracle_HOME}/jdbc/lib/ojdbc14.jar:${Oracle_HOME}/jdbc/lib/nls_charset12.jar; 
CLASSPATH=$CLASSPATH:/export/home/gs806e/tops/jconn2.jar:.;
export CLASSPATH
1

Vous devez les ajouter tous séparément. Alternativement, si vous vraiment devez simplement spécifier un répertoire, vous pouvez tout détourner dans un répertoire et l'ajouter à votre chemin de classe. Je ne recommande toutefois pas cette approche, car vous risquez des problèmes bizarres en matière de gestion de version de chemins d'accès aux classes et d'inviolabilité.

1
Daniel Spiewak

Pensez à un fichier jar en tant que racine d'une structure de répertoires. Oui, vous devez tous les ajouter séparément.

1
R. Van Hoose

J'ai plusieurs bocaux dans un dossier. La commande ci-dessous a fonctionné pour moi dans JDK1.8 pour inclure tous les fichiers JAR présents dans le dossier. S'il vous plaît noter que pour inclure des guillemets si vous avez un espace dans le classpath

Windows

Compilation: javac -classpath "C:\My Jars\sdk\lib\*" c:\programs\MyProgram.Java

En cours d'exécution: Java -classpath "C:\My Jars\sdk\lib\*;c:\programs" MyProgram

Linux

Compilation: javac -classpath "/home/guestuser/My Jars/sdk/lib/*" MyProgram.Java

En cours d'exécution: Java -classpath "/home/guestuser/My Jars/sdk/lib/*:/home/guestuser/programs" MyProgram

0
vkrams

J'essaie de lancer le fichier Java en tant que jar ou en tant que classes dans Ubuntu. J'ai échoué dans les deux options. L'exception suivante est sa sortie.

Download link: https://upload.cat/f694139f88c663b1

Java org.statmetrics.Statmetric

ou

Java -cp /home/elias/statmetrics/statmetrics.jar :. org.statmetrics.Statmetrics

ou

Java -classpath "/usr/lib/jvm/Java-1.8.0-openjdk-AMD64/jre/lib/*" -jar /home/elias/statmeics/statmetrics.jar org.statmetrics.Statmetrics

Exception in thread "Thread-0" Java.lang.NoClassDefFoundError: javax/xml/bind/annotation/adapters/XmlAdapter
    at Java.base/Java.lang.ClassLoader.defineClass1(Native Method)
    at Java.base/Java.lang.ClassLoader.defineClass(ClassLoader.Java:1016)
    at Java.base/Java.security.SecureClassLoader.defineClass(SecureClassLoader.Java:174)
    at Java.base/jdk.internal.loader.BuiltinClassLoader.defineClass(BuiltinClassLoader.Java:802)
    at Java.base/jdk.internal.loader.BuiltinClassLoader.findClassOnClassPathOrNull(BuiltinClassLoader.Java:700)
    at Java.base/jdk.internal.loader.BuiltinClassLoader.loadClassOrNull(BuiltinClassLoader.Java:623)
    at Java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.Java:581)
    at Java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.Java:178)
    at Java.base/Java.lang.ClassLoader.loadClass(ClassLoader.Java:521)
    at org.statmetrics.c.a(Unknown Source)
    at org.statmetrics.dw.a(Unknown Source)
    at org.statmetrics.dx.run(Unknown Source)
Caused by: Java.lang.ClassNotFoundException: javax.xml.bind.annotation.adapters.XmlAdapter
    at Java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.Java:583)
    at Java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.Java:178)
    at Java.base/Java.lang.ClassLoader.loadClass(ClassLoader.Java:521)
    ... 12 more

J'ai trouvé la réponse:

Ma bêtise.

Première étape: vous devez définir le code Java correspondant: j’avais Java 11 mais j’ai défini comme chemin Java lib la 8e version! - Vous pouvez définir la version Java à partir d'ici:

  Sudo update-alternatives --config Java

2ème étape: Exécutez ensuite la commande suivante, en modifiant le chemin et les noms de fichiers en fichiers et chemins correspondants:

  Java -classpath "/usr/lib/jvm/Java-1.8.0-openjdk-AMD64/jre/lib/*" -jar /home/elias/statmetrics/statmetrics.jar org.statmetrics.Statmetrics

C'était couru avec succès!

0