Classpath включая JAR в JAR

134

Можно ли указать Java, classpathкоторый включает файл JAR, содержащийся в другом файле JAR?

Пол Райнерс
источник

Ответы:

94

Если вы пытаетесь создать один jar-файл, содержащий ваше приложение и необходимые библиотеки, есть два способа (которые я знаю) сделать это. Первый - One-Jar , который использует специальный загрузчик классов, чтобы разрешить вложение jar. Вторым является UberJar , (или Shade ), который взрывает включенные библиотеки и помещает все классы в jar верхнего уровня.

Я должен также упомянуть, что UberJar и Shade являются плагинами для Maven1 и Maven2 соответственно. Как упомянуто ниже, вы также можете использовать плагин сборки (который на самом деле гораздо мощнее, но гораздо сложнее правильно настроить).

Стив Мойер
источник
81
Итак, мы, 5 лет спустя. Похоже, это все еще правда. Очень печально :(
T3rm1
3
Лучший способ, который я знаю сейчас, - использовать артефакт IntelliJ jar. Он извлекает все классы из зависимых фляг и помещает их в одну флягу.
ent8enment теперь
2
Это невозможно в некоторых ситуациях, например, при использовании реализаций JCE, таких как BouncyCastle, которые необходимо подписать
debuti
1
@ BrainSlugs83 ... Что ты пытаешься сделать? Я думаю, что загрузчик классов и упаковщик One-Jar по-прежнему является ответом на включение Jar в проекты Jar (для Java SE). Использование UberJar устраняет проблему, распаковывая файлы классов в ваш Jar.
Стив Мойер
1
Ссылка UberJar требует учетных данных для входа. Есть ли веб-страница-преемник?
Томас Уэллер
50

Вы НЕ хотите использовать эти решения для "взрыва содержимого JAR". Они определенно мешают видеть вещи (так как все взорвано на одном уровне). Кроме того, могут быть конфликты имен (не должно происходить, если люди используют надлежащие пакеты, но вы не всегда можете это контролировать).

Функция, которую вы хотите, - это один из 25 лучших RFE Sun : RFE 4648386 , который Sun в своей бесконечной мудрости определила как имеющий низкий приоритет. Мы можем только надеяться, что Солнце проснется ...

Между тем, лучшее решение, с которым я столкнулся (которое я хотел бы, чтобы Sun копировал в JDK), - это использование пользовательского загрузчика классов JarClassLoader .

Брюс Уиллис
источник
4
Конфликты имен практически гарантированно случаются с такими вещами, как конфигурация log4j и тексты лицензий.
Майкл Боргвардт
1
К сожалению, JarClassLoader является GPLv3 / коммерческим, поэтому он, вероятно, не будет «скопирован солнцем (теперь оракул)», и его нельзя будет использовать в коммерческих целях, если у вас нет внутриполитического влияния и времени, чтобы что-то купить. Тем не менее, я согласен с тем, что jar-файлы, содержащие barf в текущем каталоге, - это плохо
Гас
+1 за идею в этом ответе (хотя я не буду +1 добавлять сам ответ): вы не можете повторно упаковать любой подписанный JAR-файл, поэтому этот метод не может быть использован во многих ситуациях (например, Java activation.jar).
Кристофер Шульц
31

После некоторых исследований я нашел метод, который не требует maven или какого-либо стороннего расширения / программы.

Вы можете использовать «Class-Path» в вашем файле манифеста.

Например:

Создать файл манифеста MANIFEST.MF

Manifest-Version: 1.0
Created-By: Bundle
Class-Path: ./custom_lib.jar
Main-Class: YourMainClass

Скомпилируйте все ваши классы и запустите jar cfm Testing.jar MANIFEST.MF *.class custom_lib.jar

cобозначает создание архива fуказывает, что вы хотите указать файл vдля подробного ввода m означает, что мы передадим пользовательский файл манифеста.

Убедитесь, что вы включили lib в пакет jar. Вы должны быть в состоянии запустить банку в обычном режиме.

основанный на: http://www.ibm.com/developerworks/library/j-5things6/

всю остальную информацию, необходимую вам о пути к классам, вы найдете здесь

Tezar
источник
19
Этот ответ не работает. из документа oracle (ссылка на который приведена выше): «Заголовок Class-Path указывает на классы или файлы JAR в локальной сети, а не файлы JAR в файле JAR»
sebnukem
Все, что известно, это также можно использовать в настройках Android.
Мостовский Свернуть
2
Он работает для исполняемого сценария jar (протестировано), но может не работать, если вы хотите включить jar в jar библиотеки.
Cychih
5
О, нет, это не работает, как только я custom_lib.jarотошел, банку больше нельзя выполнять :(
Cychih
Как можно указать несколько банок в Class-Path?
Абхишек Тивари
22

Используйте тег zipgroupfileset (использует те же атрибуты, что и тег fileset ); он распакует все файлы в каталоге и добавит в ваш новый файл архива. Больше информации: http://ant.apache.org/manual/Tasks/zip.html

Это очень полезный способ обойти проблему jar-in-a-jar - я знаю, потому что я нашел этот точный вопрос StackOverflow, пытаясь понять, что делать. Если вы хотите упаковать jar или папку jar в ваш собранный jar с Ant, забудьте обо всем этом, что касается classpath или сторонних плагинов, все, что вам нужно сделать, это (в Ant):

<jar destfile="your.jar" basedir="java/dir">
  ...
  <zipgroupfileset dir="dir/of/jars" />
</jar>
ecbrodie
источник
8

Если вы строите с помощью ant (я использую ant из eclipse), вы можете просто добавить дополнительные jar-файлы, сказав ant для добавления их ... Не обязательно лучший метод, если у вас есть проект, поддерживаемый несколькими людьми, но он работает для одного человека проект и легко.

например, моя цель, которая строила файл .jar:

<jar destfile="${plugin.jar}" basedir="${plugin.build.dir}">
    <manifest>
        <attribute name="Author" value="ntg"/>
        ................................
        <attribute name="Plugin-Version" value="${version.entry.commit.revision}"/>
    </manifest>
</jar>

Я просто добавил одну строку, чтобы сделать это:

<jar ....">
    <zipgroupfileset dir="${external-lib-dir}" includes="*.jar"/>
    <manifest>
        ................................
    </manifest>
</jar>

где

<property name="external-lib-dir" 
          value="C:\...\eclipseWorkspace\Filter\external\...\lib" />

был реж с наружными банками. И это все...

NTG
источник
6

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

Джо Скора
источник
2

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

Джеймс Шек
источник
2

Я использую maven для моих сборок java, в которых есть плагин под названием плагин сборки maven .

Это делает то, что вы просите, но, как и некоторые другие предложения, описывают - по сути, взорвать все зависимые банки и объединить их в одну банку

Vinnie
источник
Плагин сборки Maven довольно болезненный в использовании ... UberJar и Shade - это плагины Maven1 и Maven2 (факт, который я должен был упомянуть выше, и сделаю это сейчас)
Стив Мойер,
2

Если у вас есть eclpise IDE, вам просто нужно экспортировать JAR и выбрать «Пакет Обязательные библиотеки в сгенерированный JAR». eclipse автоматически добавит требуемые зависимые JAR-файлы в сгенерированный JAR-файл, а также сгенерирует некоторый загрузчик пользовательских классов eclipse, который автоматически загружает эти JAR-файлы.

amralieg
источник
1

Я собирался посоветовать извлечь все файлы на одном уровне, а затем сделать из этого банку, так как система пакетов должна держать их аккуратно разделенными. Это было бы ручным способом, я полагаю, что инструменты, указанные Стивом, сделают это хорошо.

PhiLho
источник
1

Ну, есть очень простой способ, если вы используете Eclipse.

Экспортируйте ваш проект в виде файла Jar «Runnable» (щелкните правой кнопкой мыши папку проекта в Eclipse, выберите «Export ...»). При настройке параметров экспорта обязательно выберите «Извлечь необходимые библиотеки в сгенерированный Jar». Имейте в виду, выберите «Извлечь ...» и не «Пакет обязательных библиотек ...».

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

В любом случае, он не гарантированно будет работать 100% времени - так как вы заметите всплывающее сообщение, в котором вам будет сказано убедиться, что вы проверяете лицензии на файлы Jar, которые вы включаете, и что-то не копировать файлы подписи. Тем не менее, я делал это годами и никогда не сталкивался с проблемой.

CM_2014
источник
0

Извлечение в Uber-dir работает для меня, так как мы все должны использовать root: \ java и иметь выходной код в пакетах с версиями. Т.е. ca.tecreations-1.0.0. Подписание в порядке, потому что банки не повреждены из их загруженного местоположения. Сторонние подписи не повреждены, извлеките их в c: \ java. Там мой проект реж. запустить из панели запуска, так что java -cp c: \ java Launcher

Тим де Врис
источник
Так что банки в c: \ java \ jars. Источник, двоичные файлы и ресурсы в c: \ java. Исключить резервные копии, свойства, keystore_private. Распакуйте в c: \ java и запустите с помощью инструмента формирования classpath, так что, возможно, ca.tecreations.system.tools.SystemTool или аналогичный класс java. Выполните это.
Тим де Врис