Включение всех jar-файлов в каталог внутри Java classpath

Есть ли способ включить все файлы JAR в каталог в classpath?

я пытаюсь java -classpath lib/*.jar:. my.package.Program и он не может найти файлы классов, которые, безусловно, находятся в этих банках. Нужно ли добавлять каждый jar-файл в classpath отдельно?

26 ответов

Используя Java 6 или новее, опция classpath поддерживает подстановочные знаки. Обратите внимание на следующее:

  • Используйте прямые кавычки (")
  • использование *не *.jar

Windows

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

Юникс

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

Это похоже на Windows, но использует : вместо ;, Если вы не можете использовать подстановочные знаки, bash позволяет следующий синтаксис (где lib каталог, содержащий все архивные файлы Java):

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

(Обратите внимание, что использование classpath несовместимо с -jar вариант. Смотрите также: Выполните файл JAR с несколькими библиотеками пути к классам из командной строки)

Понимание подстановочных знаков

Из документа Classpath:

Записи пути к классу могут содержать подстановочный знак базового имени *, что считается эквивалентным указанию списка всех файлов в каталоге с расширением .jar или же .JAR, Например, запись пути к классу foo/* определяет все файлы JAR в каталоге с именем foo. Запись пути к классу, состоящая просто из * расширяется список всех файлов JAR в текущем каталоге.

Запись пути к классу, которая содержит * не будет соответствовать файлам классов. Чтобы сопоставить как классы, так и файлы JAR в одном каталоге foo, используйте либо foo;foo/* или же foo/*;foo, Выбранный порядок определяет, будут ли классы и ресурсы в foo загружаются до JAR-файлов в foo, или наоборот.

Подкаталоги не ищутся рекурсивно. Например, foo/* ищет файлы JAR только в foo, не в foo/bar, foo/baz, так далее.

Порядок, в котором JAR-файлы в каталоге перечисляются в расширенном пути к классам, не указан и может варьироваться от платформы к платформе и даже от момента к моменту на одном и том же компьютере. Хорошо построенное приложение не должно зависеть от какого-либо конкретного порядка. Если требуется определенный порядок, тогда JAR-файлы могут быть явно перечислены в пути к классам.

Расширение подстановочных знаков выполняется рано, до вызова основного метода программы, а не поздно, во время самого процесса загрузки классов. Каждый элемент пути входного класса, содержащий подстановочный знак, заменяется (возможно, пустой) последовательностью элементов, созданной путем перечисления файлов JAR в именованном каталоге. Например, если каталог foo содержит a.jar, b.jar, а также c.jarтогда путь класса foo/* расширяется в foo/a.jar;foo/b.jar;foo/c.jarи эта строка будет значением системного свойства java.class.path,

CLASSPATH переменная окружения не обрабатывается по-другому -classpath (или же -cp) опция командной строки. То есть подстановочные знаки соблюдаются во всех этих случаях. Однако подстановочные знаки пути класса не учитываются в Class-Path jar-manifest заголовок.

Примечание: из-за известной ошибки в java 8 примеры Windows должны использовать обратную косую черту, предшествующую записи с завершающей звездочкой: https://bugs.openjdk.java.net/browse/JDK-8131329

Под окнами это работает:

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

и это не работает

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

обратите внимание на *.jar, поэтому подстановочный знак * должен использоваться один.


В Linux работает следующее:

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

Разделителями являются двоеточия, а не точки с запятой.

Мы можем обойти эту проблему, развернув основной файл JAR myapp.jar который содержит манифест (Manifest.mf) файл, указывающий путь к классам с другими необходимыми файлами jar, которые затем развертываются вместе с ним. В этом случае вам нужно только объявить java -jar myapp.jar при запуске кода.

Так что если вы развернете основной jar в некоторый каталог, а затем поместите зависимые банки в lib под этой папкой манифест выглядит так:

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

Примечание: это не зависит от платформы - мы можем использовать одни и те же файлы jar для запуска на сервере UNIX или на ПК с Windows.

Мое решение на Ubuntu 10.04 с использованием java-sun 1.6.0_24, в котором все jar-файлы находятся в каталоге "lib":

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

Если это не удается, следующая команда должна работать (выводит все *.jars в каталоге lib в параметр classpath)

java -cp $ (для i в lib/*.jar; выполнить echo -n $i:; done). my.main.Class

Короткий ответ: java -classpath lib/*:. my.package.Program

Oracle предоставляет документацию по использованию подстановочных знаков в classpath здесь для Java 6 и здесь для Java 7, в разделе, озаглавленном Понимание подстановочных знаков пути к классам. (Когда я пишу это, две страницы содержат одинаковую информацию.) Вот краткое изложение основных моментов:

  • В общем, чтобы включить все файлы JAR в данный каталог, вы можете использовать подстановочный знак * (не *.jar).

  • Подстановочный знак соответствует только файлам JAR, а не файлам классов; чтобы получить все классы в каталоге, просто завершите запись classpath в имени каталога.

  • Вышеупомянутые два параметра могут быть объединены, чтобы включить все файлы JAR и классов в каталог, и применяются обычные правила приоритета пути к классам. Например -cp /classes;/jars/*

  • Подстановочный знак не будет искать JAR-файлы в подкаталогах.

  • Приведенные выше пункты являются верными, если вы используете CLASSPATH системное свойство или -cp или же -classpath флаги командной строки. Однако, если вы используете Class-Path Заголовок манифеста JAR (как вы могли бы сделать с файлом сборки ant), подстановочные знаки не будут учитываться.

Да, моя первая ссылка такая же, как и в ответе с наивысшей оценкой (который я не надеюсь обгонять), но этот ответ не дает большого объяснения помимо ссылки. Так как в наши дни такое поведение не рекомендуется использовать в Stack Overflow, я решил расширить его.

Windows:
java -cp file.jar; dir / * my.app.ClassName

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

Напомните:
- Разделитель пути Windows - это " ; "
- Разделитель пути Linux : " : "
- В Windows, если аргумент cp не содержит пробелов, "кавычки" необязательны

Для меня это работает в Windows .

java -cp "/lib/*;" sample

Для Linux

java -cp "/lib/*:" sample

Я использую Java 6

Вы можете попробовать Java -Djava.ext.dirs=jarDirectory http://docs.oracle.com/javase/6/docs/technotes/guides/extensions/spec.html

Каталог для внешних банок при запуске Java

Исправить:

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

Неправильно:

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

Если вы используете Java 6, то вы можете использовать подстановочные знаки в пути к классам.

Теперь можно использовать подстановочные знаки в определении пути к классу:

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

Ссылка: http://www.rekk.de/bloggy/2008/add-all-jars-in-a-directory-to-classpath-with-java-se-6-using-wildcards/

Если вам действительно нужно указать все файлы.jar динамически, вы можете использовать сценарии оболочки или Apache Ant. Есть проект Commons Launcher, который в основном позволяет вам указать ваш стартовый скрипт как файл сборки ant (если вы понимаете, что я имею в виду).

Затем вы можете указать что-то вроде:

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

В вашем файле запуска запуска, который запустит ваше приложение с правильным classpath.

Обратите внимание, что расширение подстановочных знаков не работает для Java 7 в Windows.

Проверьте эту проблему Stackru для получения дополнительной информации.

Обходной путь должен поставить точку с запятой сразу после подстановочного знака. java -cp "somewhere/*;"

Для предъявления по месту требования,

Я обнаружил это странное поведение в Windows под оболочкой MSYS/MinGW.

Работает:

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

Не работает:

$ 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

Я совершенно уверен, что подстановочный знак не расширяется оболочкой, потому что, например,

$ echo './*'
./*

(Пробовал тоже с другой программой, а не со встроенной echoс тем же результатом.)

Я верю что это javac который пытается расширить его, и он ведет себя по-разному, есть ли точка с запятой в аргументе или нет. Во-первых, он может пытаться расширить все аргументы, которые выглядят как пути. И только тогда они будут разбирать их, с -cp беру только следующий токен. (Обратите внимание, что com.comsol.aco_1.0.0.jar это второй JAR в этом каталоге.) Это все предположение.

Это

$ javac -version
javac 1.7.0

Все вышеперечисленные решения прекрасно работают, если вы разрабатываете и запускаете приложение Java вне какой-либо IDE, такой как Eclipse или Netbeans.

Если вы работаете в Windows 7 и используете Eclipse IDE для разработки на Java, вы можете столкнуться с проблемами при использовании командной строки для запуска файлов классов, встроенных в Eclipse.

Например, ваш исходный код в Eclipse имеет следующую иерархию пакетов: edu.sjsu.myapp.Main.java

У вас есть json.jar как внешняя зависимость для Main.java

Когда вы попытаетесь запустить Main.java из Eclipse, он запустится без проблем.

Но когда вы попытаетесь запустить это с помощью командной строки после компиляции Main.java в Eclipse, он выдаст несколько странных ошибок, говорящих "ClassNotDef Error, бла-бла".

Я предполагаю, что вы находитесь в рабочем каталоге вашего исходного кода!!

Используйте следующий синтаксис для запуска из командной строки:

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

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

    [Не пропустите. выше]

Это потому, что вы поместили Main.java внутри пакета edu.sjsu.myapp, и java.exe будет искать точный шаблон.

Надеюсь, поможет!!

macOS, текущая папка

Для Java 13 в macOS Mojave

Если все твои .jar файлы находятся в одной папке, используйте cd чтобы сделать его вашим текущим рабочим каталогом. Проверить с pwd.

Для -classpathвы должны сначала указать файл JAR для своего приложения. Использование символа двоеточия: в качестве разделителя добавьте звездочку *чтобы получить все остальные файлы JAR в той же папке. Наконец, передайте полное имя пакета класса с вашим mainметод.

Например, для приложения в файле JAR с именем my_app.jar с main метод в классе с именем App в пакете с именем com.example, вместе с некоторыми необходимыми банками в той же папке:

java -classpath my_app.jar:* com.example.App

Краткая форма: если ваш main находится внутри jar, вам, вероятно, потребуется дополнительный '-jar pathTo/yourJar/YourJarsName.jar ', явно объявленный для его работы (даже если 'YourJarsName.jar' находился в пути к классам) (или, выраженный для ответа на первоначальный вопрос, который был задан 5 лет назад: вам не нужно явно повторно декларировать каждую банку, но, похоже, даже с java6 вам нужно переопределить вашу собственную банку...)


Длинная форма: (Я сделал это явно до такой степени, что я надеюсь, что даже нарушители Java могут использовать это)

Как и многие здесь, я использую eclipse для экспорта jar-файлов: (File->Export->'Runnable JAR File'). В предложении "Затмение библиотеки" (Juno) есть три варианта:

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"

Обычно я бы использовал opt2 (а opt1 определенно ломался), однако нативный код в одном из используемых мной jar-файлов обнаружил разрывы с помощью удобного трюка "jarinjar", который затмевает, когда вы выбираете эту опцию. Даже после того, как я понял, что мне нужен opt3, а затем нашел эту запись в Stackru, мне все еще потребовалось некоторое время, чтобы понять, как запустить мой основной за пределами затмения, так что вот что сработало для меня, так как это полезно для других...


Если вы назвали свой jar: "fooBarTheJarFile.jar" и все настроено на экспорт в каталог: "/theFully/qualPath / toYourChosenDir".

(имеется в виду поле "Экспорт назначения": "/theFully/qualifiedPath/toYourChosenDir/fooBarTheJarFile.jar")

После того, как вы нажмете финиш, вы обнаружите, что eclipse помещает все библиотеки в папку с именем 'fooBarTheJarFile_lib' в этом каталоге экспорта, давая вам что-то вроде:

/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

Затем вы можете запустить из любой точки вашей системы:

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

(Для новичков в Java: "package.path_to.the_class_with.your_main" - это объявленный путь к пакету, который вы найдете в верхней части файла "TheClassWithYourMain.java", который содержит "main(String[] args){..".}'что вы хотите запустить из-за пределов Java)


Заметим ловушку: наличие fooBarTheJarFile.jar в списке jar-файлов на объявленном пути к классу недостаточно. Вам нужно явно объявить '-jar' и повторно объявить местоположение этого jar.

например это ломает:

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

пересчитывается с относительными путями:

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   

(с использованием версии Java "1.6.0_27"; через виртуальную машину OpenJDK 64-Bit Server в Ubuntu 12.04)

Для окон кавычки обязательны и; следует использовать в качестве разделителя. например:

java -cp "target\\*;target\\dependency\\*" my.package.Main

Класс от 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

Единственный способ, которым я знаю, как сделать это индивидуально, например:

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

Надеюсь, это поможет!

Вам нужно добавить их все отдельно. В качестве альтернативы, если вам действительно нужно просто указать каталог, вы можете разархивировать все в один каталог и добавить его в свой путь к классам. Однако я не рекомендую такой подход, так как вы рискуете получить причудливые проблемы с версионностью и неуправляемостью.

Не является прямым решением для возможности установить /* в -cp, но я надеюсь, что вы могли бы использовать следующий скрипт, чтобы немного облегчить ситуацию с динамическими путями классов и каталогами 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; 

Сценарий для Linux, может иметь аналогичный для Windows тоже. Если в качестве входных данных для "libDir2Scan4jars" указан правильный каталог; скрипт отсканирует все файлы jar, создаст строку classpath и экспортирует ее в переменную env "tmpCLASSPATH".

Думайте о файле jar как о корне структуры каталогов. Да, вам нужно добавить их все по отдельности.

У меня есть несколько банок в папке. Следующая команда работает для меня в JDK1.8 включить все банки, присутствующие в папке. Обратите внимание, что включить в кавычки, если у вас есть пробел в classpath

Windows

Компиляция: javac -classpath "C:\My Jars\sdk\lib\*" c:\programs\MyProgram.java

Бег: java -classpath "C:\My Jars\sdk\lib\*;c:\programs" MyProgram

Linux

Компиляция: javac -classpath "/home/guestuser/My Jars/sdk/lib/*" MyProgram.java

Бег: java -classpath "/home/guestuser/My Jars/sdk/lib/*:/home/guestuser/programs" MyProgram

Задайте путь к классу так, чтобы он подходил для нескольких jar-файлов и файлов классов текущего каталога.

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

Порядок аргументов java команда также важна:

      c:\projects\CloudMirror>java Javaside -cp "jna-5.6.0.jar;.\"
Error: Unable to initialize main class Javaside
Caused by: java.lang.NoClassDefFoundError: com/sun/jna/Callback

против

      c:\projects\CloudMirror>java -cp "jna-5.6.0.jar;.\" Javaside
Exception in thread "main" java.lang.UnsatisfiedLinkError: Unable

Я пытаюсь запустить файл Java либо как jar, либо как классы в Ubuntu. Я потерпел неудачу в обоих вариантах. Следующим исключением является его вывод.

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

java org.statmetrics.Statmetric

или же

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

или же

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

Я нашел ответ:

Моя глупость

Первый шаг: Вы должны установить соответствующую Java: у меня была Java 11, но я установил в качестве Java lib путь 8-й версии! - Вы можете установить версию Java здесь:

  sudo update-alternatives --config java

2-й шаг: затем выполните следующую команду, изменив путь и имена файлов на соответствующие пути и файлы:

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

Это было успешно выполнено!

Другие вопросы по тегам