Percorso di classe incluso JAR all'interno di un JAR


134

È possibile specificare un Java classpathche include un file JAR contenuto in un altro file JAR?

Risposte:


94

Se stai cercando di creare un singolo jar che contenga la tua applicazione e le sue librerie richieste, ci sono due modi (di cui sono a conoscenza) per farlo. Il primo è One-Jar , che utilizza uno speciale caricatore di classi per consentire l'annidamento di vasetti. Il secondo è UberJar , (o Shade ), che esplode le librerie incluse e mette tutte le classi nel barattolo di livello superiore.

Vorrei anche menzionare che UberJar e Shade sono plugin per Maven1 e Maven2 rispettivamente. Come menzionato di seguito, puoi anche usare il plugin assembly (che in realtà è molto più potente, ma molto più difficile da configurare correttamente).


81
Quindi eccoci qui, 5 anni dopo. Sembra che sia ancora vero. Molto triste :(
T3rm1

3
Il modo migliore che conosco oggi è usare l'artefatto del vaso IntelliJ. Estrae tutte le classi dai barattoli dipendenti e le mette nel tuo unico vaso.
enl8enmentnow

2
Ciò non è possibile in alcune situazioni come quando si utilizzano implementazioni JCE come BouncyCastle che devono essere firmate
debuti,

1
@ BrainSlugs83 ... Cosa stai cercando di fare? Penso che il classloader e il packager di One-Jar sia ancora la risposta per includere un progetto Jar in a Jar (per Java SE). L'uso di UberJar elimina il problema estraendo i file di classe nel tuo Jar.
Steve Moyer,

1
Il collegamento UberJar richiede credenziali di accesso. C'è qualche pagina web successiva?
Thomas Weller,

50

NON si desidera utilizzare quelle soluzioni "esplodi contenuti JAR". Rendono sicuramente più difficile vedere le cose (dal momento che tutto è esploso allo stesso livello). Inoltre, potrebbero esserci conflitti di denominazione (non dovrebbe accadere se le persone usano pacchetti adeguati, ma non puoi sempre controllarlo).

La caratteristica che desideri è una delle 25 migliori RFE Sun : RFE 4648386 , che Sun, nella sua infinita saggezza, ha designato come di bassa priorità. Possiamo solo sperare che Sun si svegli ...

Nel frattempo, la migliore soluzione che ho trovato (che vorrei che Sun copiasse nel JDK) è usare il caricatore di classi personalizzato JarClassLoader .


4
In realtà i conflitti di denominazione sono quasi garantiti con cose come la configurazione di log4j e testi di licenza.
Michael Borgwardt,

1
Purtroppo JarClassLoader è GPLv3 / commerciale, quindi probabilmente non verrà "copiato da sun (ora oracolo)", e non può essere usato commercialmente a meno che tu non abbia il potere politico interno e il tempo per acquistare qualcosa. Sono d'accordo tuttavia che i barattoli che si trovano nella directory corrente sono una cosa negativa.
Gus,

+1 per l'idea in questa risposta (anche se non farò +1 sulla risposta stessa): non è possibile reimballare alcun file JAR firmato, quindi questa tecnica non può essere utilizzata in molte situazioni (ad esempio Java activation.jar).
Christopher Schultz,

31

Dopo alcune ricerche ho trovato un metodo che non richiede maven o alcuna estensione / programma di terze parti.

Puoi usare "Class-Path" nel tuo file manifest.

Per esempio:

Creare il file manifest MANIFEST.MF

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

Compila tutte le tue lezioni ed esegui jar cfm Testing.jar MANIFEST.MF *.class custom_lib.jar

csta per creare archivio findica che si desidera specificare il file vè per input dettagliato msignifica che passeremo un file manifest personalizzato

Assicurati di aver incluso lib nel pacchetto jar. Dovresti essere in grado di eseguire jar in modo normale.

basato su: http://www.ibm.com/developerworks/library/j-5things6/

tutte le altre informazioni di cui hai bisogno sul percorso di classe che trovi qui


19
Questa risposta non funziona. dal documento Oracle (collegato da banana sopra): "L'intestazione Path-Class punta alle classi o ai file JAR sulla rete locale, non ai file JAR all'interno del file JAR"
sebnukem,

Qualunque cosa sappia se questo può essere utilizzato anche in un'impostazione Android.
Mostowski Collapse

2
Funziona per lo scenario eseguibile jar (testato), ma potrebbe non funzionare quando si desidera includere un jar in un jar della libreria.
Cychih,

5
Oh no non funziona, una volta che mi sono custom_lib.jarallontanato, il vaso non può più essere eseguito :(
Cychih,

Come possono essere specificati più vasi nel percorso di classe?
Abhishek Tiwari,

22

Usa il tag zipgroupfileset (usa gli stessi attributi di un tag fileset ); decomprimerà tutti i file nella directory e li aggiungerà al nuovo file di archivio. Ulteriori informazioni: http://ant.apache.org/manual/Tasks/zip.html

Questo è un modo molto utile per aggirare il problema jar-in-a-jar - lo so perché ho cercato su Google questa esatta domanda StackOverflow mentre cercavo di capire cosa fare. Se vuoi impacchettare un barattolo o una cartella di vasetti nel tuo unico barattolo con Ant, allora dimentica tutto questo percorso di classe o plugin di terze parti, tutto ciò che devi fare è questo (in Ant):

<jar destfile="your.jar" basedir="java/dir">
  ...
  <zipgroupfileset dir="dir/of/jars" />
</jar>

8

Se stai costruendo con la formica (sto usando la formica da eclissi), puoi semplicemente aggiungere i file jar extra dicendo a formica di aggiungerli ... Non necessariamente il metodo migliore se hai un progetto gestito da più persone ma funziona per il progetto di una persona ed è facile.

per esempio il mio obiettivo che stava costruendo il file .jar era:

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

Ho appena aggiunto una riga per farlo:

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

dove

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

era il dir con i barattoli esterni. E questo è tutto ...


6

Non senza scrivere il tuo caricatore di classe. Puoi aggiungere vasi al percorso di classe del vaso, ma devono essere collocati nello stesso posto, non contenuti nel vaso principale.


2

È necessario creare un caricatore di classi personalizzato per eseguire questa o una libreria di terze parti che supporti questo. La soluzione migliore è estrarre il jar dal runtime e aggiungerli al percorso di classe (o averli già aggiunti al percorso di classe).


2

Uso maven per le mie build java che ha un plugin chiamato plugin assembly maven .

Fa quello che stai chiedendo, ma come alcuni degli altri suggerimenti descrivono - essenzialmente esplodendo tutti i barattoli dipendenti e ricombinandoli in un singolo barattolo


Il plugin di assemblaggio Maven è piuttosto doloroso da usare ... UberJar e Shade sono plugin Maven1 e Maven2 (un fatto che avrei dovuto menzionare sopra, e lo farò ora)
Steve Moyer

2

Se disponi di IDE eclpise, devi solo esportare il tuo JAR e scegliere "Librerie di pacchetti richiesti in JAR generato". eclipse aggiungerà automaticamente i JAR dipendenti richiesti nel JAR generato, oltre a generare un caricatore di classi personalizzate eclipse che carica automaticamente questi JAR.


1

Stavo per consigliare di estrarre tutti i file allo stesso livello, quindi di ricavare un risultato dal risultato, dal momento che il sistema di pacchetti dovrebbe tenerli ben separati. Sarebbe il modo manuale, suppongo che gli strumenti indicati da Steve lo faranno bene.



1

Bene, c'è un modo molto semplice se stai usando Eclipse.

Esporta il tuo progetto come file Jar "eseguibile" (fai clic con il pulsante destro del mouse sulla cartella del progetto da Eclipse, seleziona "Esporta ..."). Quando si configurano le impostazioni di esportazione, assicurarsi di selezionare "Estrai le librerie richieste nel Jar generato". Ricorda, seleziona "Estrai ..." e non "Librerie richieste dal pacchetto ...".

Inoltre : è necessario selezionare una configurazione di esecuzione nelle impostazioni di esportazione. Quindi, potresti sempre creare un main () vuoto in qualche classe e usarlo per la tua configurazione di esecuzione.

Ad ogni modo, non è garantito che funzioni il 100% delle volte, poiché noterai un messaggio pop-up che ti dice di assicurarti di controllare le licenze dei file Jar che stai includendo e qualcosa sul non copiare i file delle firme. Tuttavia, lo faccio da anni e non ho mai riscontrato problemi.


0

L'estrazione in una Uber-dir funziona per me come dovremmo tutti usare root: \ java e avere il codice delle uscite nei pacchetti con controllo delle versioni. Vale a dire ca.tecreations-1.0.0. La firma va bene perché i barattoli sono intatti dalla loro posizione scaricata. Firme di terze parti intatte, estratto in c: \ java. C'è il mio dir di progetto. eseguito dal programma di avvio, quindi java -cp c: \ java Launcher


Quindi vasi in c: \ java \ jars. Sorgente, file binari e risorse in c: \ java. Escludere backup, proprietà, keystore_private. Decomprimi in c: \ java ed esegui con lo strumento di formazione classpath, quindi forse ca.tecreations.system.tools.SystemTool o classe java comparabile. Eseguilo.
Tim de Vries,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.