Inclusion de dépendances dans un pot avec Maven

353

Existe-t-il un moyen de forcer maven (2.0.9) à inclure toutes les dépendances dans un seul fichier jar?

J'ai un projet les builds dans un seul fichier jar. Je veux que les classes des dépendances soient également copiées dans le pot.

Mise à jour: je sais que je ne peux pas simplement inclure un fichier jar dans un fichier jar. Je cherche un moyen de décompresser les fichiers JAR spécifiés en tant que dépendances et de regrouper les fichiers de classe dans mon fichier JAR.

coureur
la source
2
Comment inclure un fichier jar dans un fichier jar dans maven?
Kush Patel

Réponses:

488

Vous pouvez le faire en utilisant le plugin maven-assembly avec le descripteur "jar-with-dependencies". Voici le morceau pertinent de l'un de nos pom.xml qui fait cela:

  <build>
    <plugins>
      <!-- any other plugins -->
      <plugin>
        <artifactId>maven-assembly-plugin</artifactId>
        <executions>
          <execution>
            <phase>package</phase>
            <goals>
              <goal>single</goal>
            </goals>
          </execution>
        </executions>
        <configuration>
          <descriptorRefs>
            <descriptorRef>jar-with-dependencies</descriptorRef>
          </descriptorRefs>
        </configuration>
      </plugin>
    </plugins>
  </build>
John Stauffer
la source
30
L' attachedobjectif est déconseillé. Le singleou le directory-singlebut devrait être préféré à la place.
Pascal Thivent
16
directory-singleest désormais obsolète également.
James McMahon
14
l'utilisation de single est recommandée sur le site officiel
mateuszb
42
Dans le cas où de nouvelles personnes mvn seraient bloquées comme moi, ajoutez le plugin à <plugins> dans <build> qui est dans <project>.
DA
10
@ Christian.tucker Il y a un 2ème pot dans le répertoire cible créé comme ceci: ./target/example-0.0.1-SNAPSHOT.jar et ./target/example-0.0.1-SNAPSHOT-jar-with-dependencies.jar
technocrate
145

Avec Maven 2, la bonne façon de le faire est d'utiliser le plugin d'assemblage Maven2 qui a un fichier de descripteur prédéfini à cet effet et que vous pouvez simplement utiliser sur la ligne de commande:

mvn assembly:assembly -DdescriptorId=jar-with-dependencies

Si vous voulez rendre ce fichier exécutable, ajoutez simplement la classe principale à exécuter à la configuration du plugin:

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-assembly-plugin</artifactId>
  <configuration>
    <archive>
      <manifest>
        <mainClass>my.package.to.my.MainClass</mainClass>
      </manifest>
    </archive>
  </configuration>
</plugin>

Si vous souhaitez créer cet assembly dans le cadre du processus de génération normal, vous devez lier l' objectif unique ou l' annuaire unique (l' assemblyobjectif ne doit être exécuté qu'à partir de la ligne de commande) à une phase de cycle de vie ( packagelogique), quelque chose comme ceci:

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-assembly-plugin</artifactId>
  <executions>
    <execution>
      <id>create-my-bundle</id>
      <phase>package</phase>
      <goals>
        <goal>single</goal>
      </goals>
      <configuration>
        <descriptorRefs>
          <descriptorRef>jar-with-dependencies</descriptorRef>
        </descriptorRefs>
        ...
      </configuration>
    </execution>
  </executions>
</plugin>

Adaptez l' configurationélément en fonction de vos besoins (par exemple avec les éléments manifestes tels que parlés).

Pascal Thivent
la source
J'essaie exactement cela, mais le plugin n'est pas exécuté et le fichier jar n'est pas créé même si la construction s'exécute sans problème. Y a-t-il un piège commun avec lequel je pourrais être coincé?
posdef
6
Ça marche pour moi mais j'ai une quête. après la construction maintenant, deux fichiers JAR sont créés, l'un avec le projet version-artefactid et l'autre avec la version-artefactid "jar-avec-dépendances". Mais je veux qu'un seul pot soit construit. Y a-t-il un autre moyen
Souvik Bhattacharya
38

Si vous souhaitez créer un fichier jar exécutable, vous devez également définir la classe principale. La configuration complète devrait donc l'être.

    <plugins>
            <plugin>
                 <artifactId>maven-assembly-plugin</artifactId>
                 <executions>
                     <execution>
                          <phase>package</phase>
                          <goals>
                              <goal>single</goal>
                          </goals>
                      </execution>
                  </executions>
                  <configuration>
                       <!-- ... -->
                       <archive>
                           <manifest>
                                 <mainClass>fully.qualified.MainClass</mainClass>
                           </manifest>
                       </archive>
                       <descriptorRefs>
                           <descriptorRef>jar-with-dependencies</descriptorRef>
                      </descriptorRefs>
                 </configuration>
         </plugin>
   </plugins>
abdiel
la source
2
Pourquoi le nom du pot est-il ajouté par "pot avec dépendances"?! Des solutions?
Tina J
1
@Tina J vous pouvez ajouter <appendAssemblyId>false</appendAssemblyId>à l'intérieur de la <configuration>balise pour exclure le suffixe "-jar-with-dependencies" dans le nom final.
ccu
19

Il y a le plugin shadow maven . Il peut être utilisé pour empaqueter et renommer les dépendances (pour omettre les problèmes de dépendance sur le chemin de classe).

Thomas Jung
la source
2
si vous n'aimez pas jar-with-dependencies dans le cadre du nom de fichier.
Kyle
minimiser la fonctionnalité maven.apache.org/plugins/maven-shade-plugin/examples/…
Alex78191
ce fut la meilleure réponse pour moi .. :)
Anand Varkey Philips
17

Vous pouvez utiliser le pot nouvellement créé à l'aide d'une <classifier>balise.

<dependencies>
    <dependency>
        <groupId>your.group.id</groupId>
        <artifactId>your.artifact.id</artifactId>
        <version>1.0</version>
        <type>jar</type>
        <classifier>jar-with-dependencies</classifier>
    </dependency>
</dependencies>
lasantha
la source
14

Si vous (comme moi) n'aimez pas particulièrement l' approche jar-with-dependencies décrite ci-dessus, la solution maven que je préfère est de simplement construire un projet WAR, même si ce n'est qu'une application Java autonome que vous construisez:

  1. Faites un projet jar maven normal, qui va construire votre fichier jar (sans les dépendances).

  2. En outre, configurez un projet de guerre maven (avec uniquement un fichier src / main / webapp / WEB-INF / web.xml vide , ce qui évitera un avertissement / une erreur dans la construction maven), qui n'a que votre projet jar comme une dépendance, et faites de votre projet de pot un <module>sous votre projet de guerre. (Ce projet de guerre n'est qu'une simple astuce pour envelopper toutes vos dépendances de fichier jar dans un fichier zip.)

  3. Générez le projet war pour produire le fichier war.

  4. Dans l'étape de déploiement, renommez simplement votre fichier .war en * .zip et décompressez-le.

Vous devriez maintenant avoir un répertoire lib (que vous pouvez déplacer où vous le voulez) avec votre jar et toutes les dépendances dont vous avez besoin pour exécuter votre application:

java -cp 'path/lib/*' MainClass

(Le caractère générique dans classpath fonctionne en Java-6 ou supérieur)

Je pense que cela est à la fois plus simple à configurer dans maven (pas besoin de jouer avec le plugin d'assemblage) et vous donne également une vue plus claire de la structure de l'application (vous verrez les numéros de version de tous les pots dépendants en clair, et éviter de tout obstruer dans un seul fichier jar).

Rop
la source
Est-ce la même chose qu'Eclipse "Exporter en tant que pot exécutable"? Parce qu'avec cela, vous pouvez choisir de "regrouper toutes les dépendances avec le JAR", vous obtenez alors toutes les dépendances dans le dossier project-lib, le long de votre jar.
WesternGun
@FaithReaper - Ce pourrait être "le même", je n'ai jamais essayé ça. Mais je suppose que si vous utilisez Eclipse, ce n'est pas facilement scriptable, ce qui est une exigence, si vous voulez implémenter un build + deploy-pipeline automatisé . Par exemple, laissez Jenkins-server faire la construction à partir de votre git source-repository, ou similaire.
Rop
12

http://fiji.sc/Uber-JAR fournit une excellente explication des alternatives:

Il existe trois méthodes courantes pour construire un uber-JAR:

  1. Non ombré. Décompressez tous les fichiers JAR, puis reconditionnez-les dans un seul JAR.
    • Pro: Fonctionne avec le chargeur de classe par défaut de Java.
    • Inconvénients: les fichiers présents dans plusieurs fichiers JAR avec le même chemin (par exemple, META-INF / services / javax.script.ScriptEngineFactory) se remplaceront mutuellement, ce qui entraînera un comportement défectueux.
    • Outils: Plugin d'assemblage Maven, Classworlds Uberjar
  2. Ombré. Identique à non ombré, mais renommez (c'est-à-dire "ombre") tous les packages de toutes les dépendances.
    • Pro: Fonctionne avec le chargeur de classe par défaut de Java. Évite certains (pas tous) conflits de versions de dépendances.
    • Inconvénients: les fichiers présents dans plusieurs fichiers JAR avec le même chemin (par exemple, META-INF / services / javax.script.ScriptEngineFactory) se remplaceront mutuellement, ce qui entraînera un comportement défectueux.
    • Outils: Maven Shade Plugin
  3. JAR de JAR. Le fichier JAR final contient les autres fichiers JAR intégrés.
    • Pro: évite les conflits de version de dépendance. Tous les fichiers de ressources sont conservés.
    • Con: Doit regrouper un chargeur de classe spécial "bootstrap" pour permettre à Java de charger des classes à partir des fichiers JAR encapsulés. Le débogage des problèmes de chargeur de classe devient plus complexe.
    • Outils: exportateur de fichiers JAR Eclipse, One-JAR.
André Valenti
la source
1
Ce n'est pas tout à fait vrai en ce qui concerne les services, le plugin d'ombre a des transformateurs et l'un d'eux est pour concaténer le contenu des fichiers dans le META-INF/servicesrépertoire. Plus d'infos ici: maven.apache.org/plugins/maven-shade-plugin/examples/…
vitro
7
        <!-- Method 1 -->
        <!-- Copy dependency libraries jar files to a separated LIB folder -->
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-dependency-plugin</artifactId>
            <configuration>
                <outputDirectory>${project.build.directory}/lib</outputDirectory>
                <excludeTransitive>false</excludeTransitive> 
                <stripVersion>false</stripVersion>
            </configuration>
            <executions>
                <execution>
                    <id>copy-dependencies</id>
                    <phase>package</phase>
                    <goals>
                        <goal>copy-dependencies</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
        <!-- Add LIB folder to classPath -->
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-jar-plugin</artifactId>
            <version>2.4</version>
            <configuration>
                <archive>
                    <manifest>
                        <addClasspath>true</addClasspath>
                        <classpathPrefix>lib/</classpathPrefix>
                    </manifest>
                </archive>
            </configuration>
        </plugin>


        <!-- Method 2 -->
        <!-- Package all libraries classes into one runnable jar -->
        <plugin>
            <artifactId>maven-assembly-plugin</artifactId>
            <executions>
              <execution>
                <phase>package</phase>
                <goals>
                  <goal>single</goal>
                </goals>
              </execution>
            </executions>
            <configuration>
              <descriptorRefs>
                <descriptorRef>jar-with-dependencies</descriptorRef>
              </descriptorRefs>
            </configuration>
        </plugin>            
Leslie Li
la source
4

Ma solution définitive sur Eclipse Luna et m2eclipse: chargeur de classe personnalisé (télécharger et ajouter à votre projet, 5 classes uniquement): http://git.eclipse.org/c/jdt/eclipse.jdt.ui.git/plain/org. eclipse.jdt.ui / jar% 20in% 20jar% 20loader / org / eclipse / jdt / internal / jarinjarloader / ; ce chargeur de classe est le meilleur du chargeur de classe à un pot et très rapide;

<project.mainClass>org.eclipse.jdt.internal.jarinjarloader.JarRsrcLoader</project.mainClass> <project.realMainClass>my.Class</project.realMainClass>

Modifier dans JIJConstants "Rsrc-Class-Path" en "Class-Path"
mvn clean dependency: le package copy-dependencies
est créé un pot avec les dépendances dans le dossier lib avec un chargeur de classe léger

<build>
    <resources>
        <resource>
            <directory>src/main/java</directory>
            <includes>
                <include>**/*.java</include>
                <include>**/*.properties</include>
            </includes>
        </resource>
        <resource>
            <directory>src/main/resources</directory>
            <filtering>true</filtering>
            <includes>
                <include>**/*</include>
            </includes>
            <targetPath>META-INF/</targetPath>
        </resource>
        <resource>
            <directory>${project.build.directory}/dependency/</directory>
            <includes>
                <include>*.jar</include>
            </includes>
            <targetPath>lib/</targetPath>
        </resource>
    </resources>
<pluginManagement>
        <plugins>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <configuration>
                    <archive>
                        <manifest>
                            <addClasspath>true</addClasspath>
                            <mainClass>${project.mainClass}</mainClass>
                            <classpathPrefix>lib/</classpathPrefix>
                        </manifest>

                        <manifestEntries>
                            <Rsrc-Main-Class>${project.realMainClass}  </Rsrc-Main-Class>
                            <Class-Path>./</Class-Path>
                        </manifestEntries>

                    </archive>
                </configuration>
            </plugin>
<plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-dependency-plugin</artifactId>
                <executions>
                    <execution>
                        <id>copy-dependencies</id>
                        <phase>package</phase>
                        <goals>
                            <goal>copy-dependencies</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </pluginManagement>
</build>
Glaucio Southier
la source
le maven-dependency-plugin <outputDirectory> ne fonctionne pas, écrivez toujours sur le dossier "dependency"
Glaucio Southier
créer un bocal avec un dossier interne "dépendance" contenant les dépendances du projet et le mettre sur MANIFEST.MF
Glaucio Southier
<resources> <resource> <directory> src / main / java </directory> <includes> <include> ** / *. java </include> <include> ** / *. properties </include> </ comprend > </resource> <resource> <directory> src / main / resources </directory> <filtering> true </filtering> <includes> <include> ** / * </include> </includes> <targetPath> META -INF / </targetPath> </resource> <resource> <directory> $ {project.build.directory} / dependency / </directory> <includes> <include> * .jar </include> </includes> < targetPath> lib / </targetPath> </resource> </resources>
Glaucio Southier
1
Sur la base de cette réponse, j'ai créé ce projet. Vous ne devriez rien changer sauf le fichier pom: github.com/raisercostin/jarinjarloader
raisercostin
0

Ce message est peut-être un peu ancien, mais j'ai également eu le même problème récemment. La première solution proposée par John Stauffer est bonne, mais j'ai eu quelques problèmes en travaillant ce printemps. Les jars de dépendance du printemps que j'utilise ont des fichiers de propriétés et une déclaration de schémas xml qui partagent les mêmes chemins et noms. Bien que ces pots proviennent des mêmes versions, le pot avec dépendances maven-goal remplaçait ce fichier par le dernier fichier trouvé.

Au final, l'application n'a pas pu démarrer car les pots à ressort n'ont pas pu trouver les bons fichiers de propriétés. Dans ce cas, la solution proposée par Rop a résolu mon problème.

Depuis lors, le projet Spring-Boot existe désormais. Il a un moyen très cool de gérer ce problème en fournissant un objectif maven qui surcharge l'objectif du package et fournit son propre chargeur de classe. Voir le guide de référence des bottines à ressorts

François Gergaud
la source
0

Jetez un œil à cette réponse:

Je crée un programme d'installation qui s'exécute en tant que fichier Java JAR et il doit décompresser les fichiers WAR et JAR aux endroits appropriés du répertoire d'installation. Le plugin de dépendance peut être utilisé dans la phase de package avec l'objectif de copie et il téléchargera n'importe quel fichier dans le référentiel Maven (y compris les fichiers WAR) et les enregistrera où vous en aurez besoin. J'ai changé le répertoire de sortie en $ {project.build.directory} / classes et le résultat final est que la tâche JAR normale inclut très bien mes fichiers. Je peux ensuite les extraire et les écrire dans le répertoire d'installation.

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
    <execution>
        <id>getWar</id>
        <phase>package</phase>
        <goals>
            <goal>copy</goal>
        </goals>
        <configuration>
            <artifactItems>
                <artifactItem>
                    <groupId>the.group.I.use</groupId>
                    <artifactId>MyServerServer</artifactId>
                    <version>${env.JAVA_SERVER_REL_VER}</version>
                    <type>war</type>
                    <destFileName>myWar.war</destFileName>
                </artifactItem>
            </artifactItems>
            <outputDirectory>${project.build.directory}/classes</outputDirectory>
        </configuration>
    </execution>
</executions>

millebi
la source
0

Merci j'ai ajouté l'extrait ci-dessous dans le fichier POM.xml et le problème Mp résolu et crée un fichier jar fat qui inclut tous les jars dépendants.

<plugin>
    <artifactId>maven-assembly-plugin</artifactId>
        <executions>
            <execution>
                <phase>package</phase>
                <goals>
                    <goal>single</goal>
                </goals>
            </execution>
        </executions>
        <configuration>
            <descriptorRefs>
                <descriptorRef>dependencies</descriptorRef>
            </descriptorRefs>
        </configuration>
    </plugin>
</plugins>
Rajeev Rathor
la source