Включение всех 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
Если вам действительно нужно указать все файлы.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, бла-бла".
Я предполагаю, что вы находитесь в рабочем каталоге вашего исходного кода!!
Используйте следующий синтаксис для запуска из командной строки:
javac -cp ".; json.jar" Main.java
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
Это было успешно выполнено!