Classpath, w tym JAR w JAR

134

Czy można określić Java, classpathktóra zawiera plik JAR zawarty w innym pliku JAR?

Paul Reiners
źródło

Odpowiedzi:

94

Jeśli próbujesz utworzyć pojedynczy jar zawierający twoją aplikację i wymagane biblioteki, istnieją dwa sposoby (o których wiem), aby to zrobić. Pierwszym z nich jest One-Jar , który używa specjalnego modułu ładującego klasy, aby umożliwić zagnieżdżanie słoików. Drugi to UberJar (lub Shade ), który eksploduje dołączone biblioteki i umieszcza wszystkie klasy w słoiku najwyższego poziomu.

Powinienem również wspomnieć, że UberJar i Shade to wtyczki odpowiednio dla Maven1 i Maven2. Jak wspomniano poniżej, możesz również użyć wtyczki assemblera (która w rzeczywistości jest znacznie potężniejsza, ale znacznie trudniejsza do poprawnej konfiguracji).

Steve Moyer
źródło
81
Więc oto jesteśmy, 5 lat później. Wygląda na to, że to nadal prawda. Bardzo smutne :(
T3rm1
3
Najlepszym sposobem, jaki znam, jest użycie artefaktu jar IntelliJ. Wyodrębnia wszystkie klasy z zależnych słoików i umieszcza je w jednym słoiku.
powiększenie
2
Nie jest to możliwe w niektórych sytuacjach, na przykład gdy używasz implementacji JCE, takich jak BouncyCastle, które muszą być podpisane
debiut:
1
@ BrainSlugs83 ... Co próbujesz zrobić? Myślę, że classloader i packager One-Jar jest nadal odpowiedzią na włączenie Jar w projektach Jar (dla Java SE). Korzystanie z UberJar eliminuje problem, wyodrębniając pliki klas do Jar.
Steve Moyer
1
Łącze UberJar wymaga danych logowania. Czy istnieje następna strona internetowa?
Thomas Weller
50

NIE chcesz używać tych rozwiązań „eksplodowania zawartości JAR”. Zdecydowanie utrudniają dostrzeżenie rzeczy (ponieważ wszystko eksploduje na tym samym poziomie). Ponadto mogą wystąpić konflikty nazw (nie powinno się zdarzyć, jeśli ludzie używają odpowiednich pakietów, ale nie zawsze możesz to kontrolować).

Funkcja, której potrzebujesz, to jeden z 25 najpopularniejszych Sun RFE : RFE 4648386 , który Sun, w swojej nieskończonej mądrości, określił jako mający niski priorytet. Możemy mieć tylko nadzieję, że słońce się obudzi ...

W międzyczasie najlepszym rozwiązaniem, z jakim się spotkałem (które chciałbym, aby Sun skopiował w JDK) jest użycie niestandardowego modułu ładującego klasy JarClassLoader .

Bruce Willis
źródło
4
Konflikty nazw są w rzeczywistości prawie gwarantowane w przypadku takich rzeczy, jak konfiguracja log4j i teksty licencji.
Michael Borgwardt
1
Niestety JarClassLoader jest GPLv3 / komercyjny, więc prawdopodobnie nie zostanie „skopiowany przez słońce (teraz wyrocznię)” i nie może być używany komercyjnie, chyba że masz wewnętrzne wpływy polityczne i czas, aby coś kupić. Zgadzam się jednak, że słoiki, które barf w bieżącym katalogu są złe.
Gus
+1 dla pomysłu w tej odpowiedzi (chociaż nie będę dawał +1 samej odpowiedzi): nie możesz przepakować żadnego podpisanego pliku JAR, więc ta technika nie może być używana w wielu sytuacjach (np. activation.jar).
Christopher Schultz
31

Po kilku badaniach znalazłem metodę, która nie wymaga mavena ani żadnego rozszerzenia / programu innej firmy.

Możesz użyć „Class-Path” w swoim pliku manifestu.

Na przykład:

Utwórz plik manifestu MANIFEST.MF

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

Skompiluj wszystkie swoje zajęcia i uruchom jar cfm Testing.jar MANIFEST.MF *.class custom_lib.jar

coznacza tworzenie archiwum foznacza, że ​​chcesz określić, że plik vjest przeznaczony do pełnych danych wejściowych, co moznacza, że ​​przekażemy niestandardowy plik manifestu

Upewnij się, że dołączyłeś lib do pakietu jar. Powinieneś być w stanie uruchomić słoik w normalny sposób.

na podstawie: http://www.ibm.com/developerworks/library/j-5things6/

wszystkie inne potrzebne informacje o ścieżce klasowej można znaleźć tutaj

Tezar
źródło
19
Ta odpowiedź nie działa. z dokumentu Oracle (link powyżej banana): „Nagłówek Class-Path wskazuje na klasy lub pliki JAR w sieci lokalnej, a nie na pliki JAR w pliku JAR”
sebnukem
Wszystko, co wiadomo, czy można tego również używać w ustawieniach Androida.
Mostowski Collapse
2
Działa w przypadku wykonywalnego scenariusza jar (przetestowany), ale może nie działać, gdy chcesz dołączyć jar do biblioteki jar.
Cychih
5
O nie, to nie działa, jak się wyprowadziłem custom_lib.jar, słoika nie można już
uruchomić
W jaki sposób można określić wiele plików jar w ścieżce klasy?
Abhishek Tiwari
22

Użyj znacznika zipgroupfileset (używa tych samych atrybutów co znacznik zestawu plików ); rozpakuje wszystkie pliki w katalogu i doda je do nowego pliku archiwum. Więcej informacji: http://ant.apache.org/manual/Tasks/zip.html

Jest to bardzo przydatny sposób na obejście problemu słoika w słoiku - wiem, ponieważ przeszukałem w Google to dokładne pytanie StackOverflow, próbując dowiedzieć się, co zrobić. Jeśli chcesz spakować słoik lub folder słoików do swojego jednego zbudowanego słoika z Antem, zapomnij o całej tej ścieżce klas lub wtyczkach innych firm, wszystko, co musisz zrobić, to (w Ant):

<jar destfile="your.jar" basedir="java/dir">
  ...
  <zipgroupfileset dir="dir/of/jars" />
</jar>
ecbrodie
źródło
8

Jeśli budujesz z mrówką (używam mrówki z zaćmienia), możesz po prostu dodać dodatkowe pliki jar, mówiąc mrówce, aby je dodała ... Niekoniecznie najlepsza metoda, jeśli masz projekt obsługiwany przez wiele osób, ale działa dla jednej osoby projekt i jest łatwe.

na przykład moim celem, który budował plik .jar, był:

<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>

Właśnie dodałem jedną linię, aby to zrobić:

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

gdzie

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

był reż z zewnętrznymi słojami. I to wszystko...

ntg
źródło
6

Nie bez napisania własnego programu ładującego klasy. Możesz dodać słoiki do ścieżki klas słoika, ale muszą one znajdować się w tym samym miejscu, a nie znajdować się w głównym słoiku.

Joe Skora
źródło
2

Aby to zrobić, musisz zbudować niestandardowy program ładujący klasy lub bibliotekę innej firmy, która to obsługuje. Najlepszym rozwiązaniem jest wyodrębnienie słoika ze środowiska wykonawczego i dodanie go do ścieżki klas (lub dodanie ich do ścieżki klas).

James Schek
źródło
2

Używam mavena do moich kompilacji java, które mają wtyczkę zwaną wtyczką zespołu maven .

Robi to, o co prosisz, ale tak jak opisują niektóre inne sugestie - zasadniczo eksploduje wszystkie zależne słoiki i ponownie łączy je w jeden słoik

Vinnie
źródło
Wtyczka montażowa Maven jest dość bolesna w użyciu ... UberJar i Shade to wtyczki Maven1 i Maven2 (fakt, o którym powinienem był wspomnieć powyżej i zrobię to teraz)
Steve Moyer
2

Jeśli masz środowisko eclpise IDE, wystarczy wyeksportować plik JAR i wybrać opcję „Biblioteki wymagane w pakiecie do wygenerowanego pliku JAR”. eclipse automatycznie doda wymagane zależne pliki JAR do wygenerowanego pliku JAR, a także wygeneruje program ładujący niestandardową klasę eclipse, który automatycznie ładuje te pliki JAR.

amralieg
źródło
1

Miałem właśnie poradzić, aby wyodrębnić wszystkie pliki na tym samym poziomie, a następnie zrobić z wyniku jar, ponieważ system pakietów powinien je starannie oddzielić. To byłby sposób ręczny, przypuszczam, że narzędzia wskazane przez Steve'a dobrze to zrobią.

PhiLho
źródło
1

Cóż, jeśli używasz Eclipse, istnieje bardzo łatwy sposób.

Wyeksportuj swój projekt jako „Runnable” plik Jar (kliknij prawym przyciskiem myszy folder projektu w Eclipse, wybierz „Eksportuj ...”). Podczas konfigurowania ustawień eksportu pamiętaj o zaznaczeniu opcji „Wyodrębnij wymagane biblioteki do wygenerowanego Jar”. Pamiętaj, wybierz „Wyodrębnij ...”, a nie „Spakuj wymagane biblioteki ...”.

Dodatkowo : w ustawieniach eksportu należy wybrać konfigurację uruchamiania. Tak więc zawsze możesz utworzyć pustą funkcję main () w jakiejś klasie i użyć jej do konfiguracji uruchamiania.

W każdym razie nie ma gwarancji , że będzie działać przez 100% czasu - ponieważ zauważysz wyskakujący komunikat z informacją, aby sprawdzić licencje plików Jar, które dołączasz, i coś o nie kopiowaniu plików podpisów. Jednak robię to od lat i nigdy nie napotkałem problemu.

CM_2014
źródło
0

Rozpakowywanie do katalogu Uber działa dla mnie, ponieważ wszyscy powinniśmy używać root: \ java i mieć kod gniazd w pakietach z wersjonowaniem. To znaczy ca.tecreations-1.0.0. Podpisywanie jest w porządku, ponieważ słoiki są nienaruszone z miejsca ich pobrania. Podpisy osób trzecich nienaruszone, rozpakuj do c: \ java. Oto mój projekt reż. uruchomić z programu uruchamiającego, więc java -cp c: \ java Launcher

Tim de Vries
źródło
Więc jars w c: \ java \ jars. Źródło, pliki binarne i zasoby w c: \ java. Wyklucz kopie zapasowe, właściwości, keystore_private. Rozpakuj do c: \ java i uruchom z narzędziem do tworzenia ścieżek klas, więc może ca.tecreations.system.tools.SystemTool lub porównywalna klasa java. Wykonaj to.
Tim de Vries