Comment puis-je créer un JAR exécutable avec des dépendances à l'aide de Maven?

2398

Je souhaite regrouper mon projet dans un seul fichier JAR exécutable pour distribution.

Comment puis-je faire un package de projet Maven tous les fichiers JAR de dépendance dans mon fichier JAR de sortie?

soemirno
la source
14
Veuillez expliquer à quel objectif du plugin de dépendance vous faites référence. Je ne connais aucun objectif qui fasse ce que demande la question d'origine: mettre toutes les dépendances soit A) à l'intérieur du pot d'auteurs via le reconditionnement, soit B) faire un pot exécutable qui a les autres dans un chemin de classe de MANIFEST.MF
Matthew McCullough
2
Vous pourriez trouver cette rationaljava.com/2015/02/…
Dan

Réponses:

2361
<build>
  <plugins>
    <plugin>
      <artifactId>maven-assembly-plugin</artifactId>
      <configuration>
        <archive>
          <manifest>
            <mainClass>fully.qualified.MainClass</mainClass>
          </manifest>
        </archive>
        <descriptorRefs>
          <descriptorRef>jar-with-dependencies</descriptorRef>
        </descriptorRefs>
      </configuration>
    </plugin>
  </plugins>
</build>

et vous l'exécutez avec

mvn clean compile assembly:single

L'objectif de compilation doit être ajouté avant l'assemblage: seul ou sinon le code de votre propre projet n'est pas inclus.

Voir plus de détails dans les commentaires.


Généralement, cet objectif est lié à une phase de génération pour s'exécuter automatiquement. Cela garantit que le fichier JAR est créé lors de l'exécution mvn installou de l'exécution d'un déploiement / d'une version.

<plugin>
  <artifactId>maven-assembly-plugin</artifactId>
  <configuration>
    <archive>
      <manifest>
        <mainClass>fully.qualified.MainClass</mainClass>
      </manifest>
    </archive>
    <descriptorRefs>
      <descriptorRef>jar-with-dependencies</descriptorRef>
    </descriptorRefs>
  </configuration>
  <executions>
    <execution>
      <id>make-assembly</id> <!-- this is used for inheritance merges -->
      <phase>package</phase> <!-- bind to the packaging phase -->
      <goals>
        <goal>single</goal>
      </goals>
    </execution>
  </executions>
</plugin>
IAdapter
la source
22
Merci @IAdapter. Notez que vous devriez toujours faire une compilation au préalable car cela ne fera que mettre tout ce qui est dans "target / classes" dans le JAR. Cela garantira que le fichier JAR inclut toutes les modifications que vous avez récemment apportées au code source. Donc, vous devez faire quelque chose comme: mvn clean compile assembly:single.
Michael
10
J'ai modifié la question pour inclure la liaison de phase. J'ai supprimé l'objectif d'assemblage obsolète, car personne n'a besoin de le savoir.
Duncan Jones
2
Je vois que cela n'ajoute pas les pots au pot uber, au lieu de cela, cela ajoute simplement tous les fichiers de classe au pot.
pitchblack408
170
Astuce: vous pouvez également ajouter l'élément <appendAssemblyId>false</appendAssemblyId>dans le configurationpour éviter le suffixe ennuyeux "-jar-with-dependencies" dans le nom
maxivis
6
oubliez compileet vous êtes foutu.
Prayagupd
350

Vous pouvez utiliser le plug-in de dépendance pour générer toutes les dépendances dans un répertoire distinct avant la phase de package, puis l'inclure dans le chemin de classe du manifeste:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-dependency-plugin</artifactId>
    <executions>
        <execution>
            <id>copy-dependencies</id>
            <phase>prepare-package</phase>
            <goals>
                <goal>copy-dependencies</goal>
            </goals>
            <configuration>
                <outputDirectory>${project.build.directory}/lib</outputDirectory>
                <overWriteReleases>false</overWriteReleases>
                <overWriteSnapshots>false</overWriteSnapshots>
                <overWriteIfNewer>true</overWriteIfNewer>
            </configuration>
        </execution>
    </executions>
</plugin>
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-jar-plugin</artifactId>
    <configuration>
        <archive>
            <manifest>
                <addClasspath>true</addClasspath>
                <classpathPrefix>lib/</classpathPrefix>
                <mainClass>theMainClass</mainClass>
            </manifest>
        </archive>
    </configuration>
</plugin>

Vous pouvez également utiliser ${project.build.directory}/classes/libcomme OutputDirectory pour intégrer tous les fichiers jar dans le jar principal, mais vous devrez ensuite ajouter du code de chargement de classe personnalisé pour charger les jars.

André Aronsen
la source
3
+1 Excellent. La raison pour laquelle j'utilise maven-dependency-plugin au lieu de maven-assembly-plugin est que j'utilise également buildnumber-maven-plugin, et de cette façon je peux stocker le numéro de version dans le manifeste de chaque jar individuellement.
PapaFreud
17
J'aime votre solution. J'utilise ${project.build.directory}/classes/libas outputDirectorypour avoir un .jar principal avec toutes les dépendances à l'intérieur, mais - Comment ajouter du code de chargement de classe personnalisé pour charger ces pots? Je dois faire l' exécution du travail comme: java -jar main-jar-with-deps.jar. Est-ce possible ?
marioosh
3
@ André Aronsen, j'ai utilisé cette solution pour ajouter les dépendances dans un dossier lib à l'intérieur du bocal, mais je reçois toujours une classe non trouvée, pouvez-vous s'il vous plaît nous dire comment résoudre ce problème.
Mahmoud Saleh
11
+1 à vous !! On dirait que le plugin d'assemblage maven 'jar-with-dependencies' ne fonctionne pas vraiment bien. Il me manquait quelques entrées de META-INF / spring.schemas dans le pot généré. J'ai donc mis au rebut le pot avec dépendances et utilisé votre solution ci-dessus. Parfait merci!!!
Derek
9
Pour toute autre personne rencontrant ce problème, vous devez inclure le dossier lib dans le même répertoire avec votre pot où que vous transportiez le pot.
Sparticles
224

J'ai blogué sur différentes façons de le faire.

Voir Pot exécutable avec Apache Maven (WordPress)

ou un exécutable-pot-avec-maven-exemple (GitHub)

Remarques

Ces avantages et inconvénients sont fournis par Stephan .


Pour un déploiement manuel

  • Avantages
  • Les inconvénients
    • Les dépendances sont hors du pot final.

Copier les dépendances dans un répertoire spécifique

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-dependency-plugin</artifactId>
  <executions>
    <execution>
      <id>copy-dependencies</id>
      <phase>prepare-package</phase>
      <goals>
        <goal>copy-dependencies</goal>
      </goals>
      <configuration>
        <outputDirectory>${project.build.directory}/${project.build.finalName}.lib</outputDirectory>
      </configuration>
    </execution>
  </executions>
</plugin>

Rendre le fichier exécutable Jar et le chemin de classe sensibles

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

À ce stade, le jarest réellement exécutable avec des éléments de chemin de classe externes.

$ java -jar target/${project.build.finalName}.jar

Créer des archives déployables

Le jarfichier n'est exécutable qu'avec le ...lib/répertoire frère . Nous devons créer des archives à déployer avec l'annuaire et son contenu.

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-antrun-plugin</artifactId>
  <executions>
    <execution>
      <id>antrun-archive</id>
      <phase>package</phase>
      <goals>
        <goal>run</goal>
      </goals>
      <configuration>
        <target>
          <property name="final.name" value="${project.build.directory}/${project.build.finalName}"/>
          <property name="archive.includes" value="${project.build.finalName}.${project.packaging} ${project.build.finalName}.lib/*"/>
          <property name="tar.destfile" value="${final.name}.tar"/>
          <zip basedir="${project.build.directory}" destfile="${final.name}.zip" includes="${archive.includes}" />
          <tar basedir="${project.build.directory}" destfile="${tar.destfile}" includes="${archive.includes}" />
          <gzip src="${tar.destfile}" destfile="${tar.destfile}.gz" />
          <bzip2 src="${tar.destfile}" destfile="${tar.destfile}.bz2" />
        </target>
      </configuration>
    </execution>
  </executions>
</plugin>

Maintenant, vous avez target/${project.build.finalName}.(zip|tar|tar.bz2|tar.gz)chacun contenant le jaret lib/*.


Plugin d'assemblage Apache Maven

  • Avantages
  • Les inconvénients
    • Pas de prise en charge de la relocalisation de classe (utilisez maven-shadow-plugin si une relocalisation de classe est nécessaire).
<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-assembly-plugin</artifactId>
  <executions>
    <execution>
      <phase>package</phase>
      <goals>
        <goal>single</goal>
      </goals>
      <configuration>
        <archive>
          <manifest>
            <mainClass>${fully.qualified.main.class}</mainClass>
          </manifest>
        </archive>
        <descriptorRefs>
          <descriptorRef>jar-with-dependencies</descriptorRef>
        </descriptorRefs>
      </configuration>
    </execution>
  </executions>
</plugin>

Vous avez target/${project.bulid.finalName}-jar-with-dependencies.jar.


Plugin Apache Maven Shade

  • Avantages
  • Les inconvénients
<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-shade-plugin</artifactId>
  <executions>
    <execution>
      <goals>
        <goal>shade</goal>
      </goals>
      <configuration>
        <shadedArtifactAttached>true</shadedArtifactAttached>
        <transformers>
          <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
            <mainClass>${fully.qualified.main.class}</mainClass>
          </transformer>
        </transformers>
      </configuration>
    </execution>
  </executions>
</plugin>

Vous avez target/${project.build.finalName}-shaded.jar.


plugin onejar-maven

  • Avantages
  • Les inconvénients
    • Pas activement soutenu depuis 2012.
<plugin>
  <!--groupId>org.dstovall</groupId--> <!-- not available on the central -->
  <groupId>com.jolira</groupId>
  <artifactId>onejar-maven-plugin</artifactId>
  <executions>
    <execution>
      <configuration>
        <mainClass>${fully.qualified.main.class}</mainClass>
        <attachToBuild>true</attachToBuild>
        <!-- https://code.google.com/p/onejar-maven-plugin/issues/detail?id=8 -->
        <!--classifier>onejar</classifier-->
        <filename>${project.build.finalName}-onejar.${project.packaging}</filename>
      </configuration>
      <goals>
        <goal>one-jar</goal>
      </goals>
    </execution>
  </executions>
</plugin>

Plugin Spring Boot Maven

  • Avantages
  • Les inconvénients
    • Ajoutez les classes potentiellement inutiles liées à Spring et Spring Boot.
<plugin>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-maven-plugin</artifactId>
  <executions>
    <execution>
      <goals>
        <goal>repackage</goal>
      </goals>
      <configuration>
        <classifier>spring-boot</classifier>
        <mainClass>${fully.qualified.main.class}</mainClass>
      </configuration>
    </execution>
  </executions>
</plugin>

Vous avez target/${project.bulid.finalName}-spring-boot.jar.

Jin Kwon
la source
2
@caiohamamura Vous pouvez cloner le référentiel GitHub et voir comment tous les profils fonctionnent.
Jin Kwon
Le problème était avec le package que j'utilisais: stackoverflow.com/a/12622037/2548351
caiohamamura
1
Je pense que c'est probablement la réponse la plus complète à ce sujet.
Petr Bodnár
139

Prenant la réponse d'Unanswered et la reformatant, nous avons:

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-jar-plugin</artifactId>
            <configuration>
                <archive>
                    <manifest>
                        <addClasspath>true</addClasspath>
                        <mainClass>fully.qualified.MainClass</mainClass>
                    </manifest>
                </archive>
            </configuration>
        </plugin>
        <plugin>
            <artifactId>maven-assembly-plugin</artifactId>
            <configuration>
                <descriptorRefs>
                    <descriptorRef>jar-with-dependencies</descriptorRef>
                </descriptorRefs>
            </configuration>
        </plugin>
    </plugins>
</build>

Ensuite, je recommanderais d'en faire une partie naturelle de votre build, plutôt que quelque chose à appeler explicitement. Pour en faire une partie intégrante de votre build, ajoutez ce plugin à votre pom.xmlet liez-le à l' packageévénement du cycle de vie. Cependant, un problème est que vous devez appeler l' assembly:singleobjectif si vous mettez cela dans votre pom.xml, tandis que vous appelleriez 'assembly: assembly' si vous l'exécutez manuellement à partir de la ligne de commande.

<project>
  [...]
  <build>
      <plugins>
          <plugin>
              <artifactId>maven-assembly-plugin</artifactId>
              <configuration>
                  <archive>
                      <manifest>
                          <addClasspath>true</addClasspath>
                          <mainClass>fully.qualified.MainClass</mainClass>
                      </manifest>
                  </archive>
                  <descriptorRefs>
                      <descriptorRef>jar-with-dependencies</descriptorRef>
                  </descriptorRefs>
              </configuration>
              <executions>
                  <execution>
                      <id>make-my-jar-with-dependencies</id>
                      <phase>package</phase>
                      <goals>
                          <goal>single</goal>
                      </goals>
                  </execution>
              </executions>
          </plugin>
      [...]
      </plugins>
    [...]
  </build>
</project>
Matthew McCullough
la source
10
L'utilisation de l'approche dans cette réponse entraîne le message d'erreur suivant: «Échec du chargement de l'attribut de manifeste de classe principale à partir de <fichier jar>», lorsque vous essayez d'exécuter le fichier JAR à l'aide de «java -jar <fichier jar>»
Elmo
3
Une partie archive du plug-in maven-jar est nécessaire <archive> <manifest> <addClasspath> true </addClasspath> <mainClass> full.qualified.MainClass </mainClass> </manifest> </archive>
Rade_303
4
Désolé, cette réponse est tout à fait fausse, la balise mainClass doit être sur l'entrée maven-assembly-plugin puisque vous appelez cela pendant l'objectif du package
Alex Lehmann
Je suis surpris, pourquoi pom.xml ne peut-il pas déjà inclure cela après l'archivage mvn: générer la commande? C'est un peu ennuyeux de copier-coller manuellement chaque fois que je crée un nouveau projet
maven
Je n'ai pas de méthode ou de classe principale, j'ai juste une classe avec fonction. comment puis-je faire un pot et l'utiliser
parlad
97

Utilisez le plug-in maven-shadow pour regrouper toutes les dépendances dans un seul uber-jar. Il peut également être utilisé pour créer un fichier exécutable en spécifiant la classe principale. Après avoir essayé d'utiliser maven-assembly et maven-jar, j'ai trouvé que ce plugin convenait le mieux à mes besoins.

J'ai trouvé ce plugin particulièrement utile car il fusionne le contenu de fichiers spécifiques au lieu de les écraser. Cela est nécessaire lorsqu'il existe des fichiers de ressources portant le même nom dans les bocaux et que le plug-in essaie de regrouper tous les fichiers de ressources

Voir l'exemple ci-dessous

      <plugins>
    <!-- This plugin provides the capability to package the artifact in an uber-jar, including its dependencies and to shade - i.e. rename - the packages of some of the dependencies. -->
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-shade-plugin</artifactId>
            <version>1.4</version>
            <executions>
                <execution>
                    <phase>package</phase>
                    <goals>
                        <goal>shade</goal>
                    </goals>
                    <configuration>
                        <artifactSet>
                        <!-- signed jars-->
                            <excludes>
                                <exclude>bouncycastle:bcprov-jdk15</exclude>
                            </excludes>
                        </artifactSet>

                         <transformers>
                            <transformer
                                implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                                <!-- Main class -->
                                <mainClass>com.main.MyMainClass</mainClass>
                            </transformer>
                            <!-- Use resource transformers to prevent file overwrites -->
                            <transformer 
                                 implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
                                <resource>properties.properties</resource>
                            </transformer>
                            <transformer
                                implementation="org.apache.maven.plugins.shade.resource.XmlAppendingTransformer">
                                <resource>applicationContext.xml</resource>
                            </transformer>
                            <transformer
                                implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
                                <resource>META-INF/cxf/cxf.extension</resource>
                            </transformer>
                            <transformer
                                implementation="org.apache.maven.plugins.shade.resource.XmlAppendingTransformer">
                                <resource>META-INF/cxf/bus-extensions.xml</resource>
                            </transformer>
                     </transformers>
                    </configuration>
                </execution>
            </executions>
        </plugin>

    </plugins>
Vijay Katam
la source
Alors, comment bcprov-jdk15.jar accède-t-il au chemin de classe lors de l'exécution, étant donné qu'il est exclu du processus d'ombrage?
Andrew Swan,
Il était tiré par cxf-rt-ws-security qui fait partie de mes dépendances
Vijay Katam
Je n'ai jamais entendu parler de ce plugin auparavant, mais cela a résolu mon problème avec les gestionnaires de ressort à l'intérieur des pots. Merci!
Alexandre L Telles
11
Ceux qui ont obtenu une exception de sécurité excluent les DSA du manifeste. Vérifiez maven.apache.org/plugins/maven-shade-plugin/examples/…
ruhsuzbaykus
+1 J'ai utilisé minijar: ueberjar dans le passé, mais le plugin minijar est désormais obsolète et remplacé par
shadow
19

J'ai longtemps utilisé le plugin d'assemblage maven , mais je n'ai pas pu trouver de solution au problème "already added, skipping". Maintenant, j'utilise un autre plugin - onejar-maven-plugin . Exemple ci-dessous ( mvn packagebuild jar):

<plugin>
    <groupId>org.dstovall</groupId>
    <artifactId>onejar-maven-plugin</artifactId>
    <version>1.3.0</version>
    <executions>
        <execution>
            <configuration>
                <mainClass>com.company.MainClass</mainClass>
            </configuration>
            <goals>
                <goal>one-jar</goal>
            </goals>
        </execution>
    </executions>
</plugin>

Vous devez ajouter un référentiel pour ce plugin:

<pluginRepositories>
    <pluginRepository>
        <id>onejar-maven-plugin.googlecode.com</id>
        <url>http://onejar-maven-plugin.googlecode.com/svn/mavenrepo</url>
    </pluginRepository>
</pluginRepositories>
marioosh
la source
comment se débarrasser des messages supplémentaires dans la sortie?
Alexandr
17

Vous pouvez utiliser le plugin maven-dependency-plugin, mais la question était de savoir comment créer un JAR exécutable. Pour ce faire, il faut apporter la modification suivante à la réponse de Matthew Franglen (btw, l'utilisation du plug-in de dépendance prend plus de temps à créer lors du démarrage à partir d'une cible propre):

<build>
    <plugins>
        <plugin>
            <artifactId>maven-jar-plugin</artifactId>
            <configuration>
                <archive>
                    <manifest>
                        <mainClass>fully.qualified.MainClass</mainClass>
                    </manifest>
                </archive>
            </configuration>
        </plugin>
        <plugin>
            <artifactId>maven-dependency-plugin</artifactId>
            <executions>
                <execution>
                    <id>unpack-dependencies</id>
                    <phase>package</phase>
                    <goals>
                        <goal>unpack-dependencies</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
    <resources>
        <resource>
            <directory>${basedir}/target/dependency</directory>
        </resource>
    </resources>
</build>

la source
16

Vous pouvez utiliser le plugin maven-shadow pour construire un pot Uber comme ci-dessous

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-shade-plugin</artifactId>
    <executions>
        <execution>
            <phase>package</phase>
            <goals>
                <goal>shade</goal>
            </goals>
        </execution>
    </executions>
</plugin>
Minisha
la source
Mais alors comment cela va-t-il être déployé pour repo?
Francesco Gualazzi
15

Une autre option si vous voulez vraiment reconditionner les autres contenus JAR dans votre seul JAR résultant est le plugin Maven Assembly . Il décompresse puis reconditionne tout dans un répertoire via <unpack>true</unpack>. Ensuite, vous auriez un deuxième passage qui l'a intégré dans un JAR massif.

Une autre option est le plugin OneJar . Cela effectue les actions de reconditionnement ci-dessus en une seule étape.

Matthew McCullough
la source
14

Vous pouvez ajouter ce qui suit à votre pom.xml :

<build>
<defaultGoal>install</defaultGoal>
<plugins>
  <plugin>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>2.3.2</version>
    <configuration>
      <source>1.6</source>
      <target>1.6</target>
    </configuration>
  </plugin>
  <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-jar-plugin</artifactId>
    <version>2.3.1</version>
    <configuration>
      <archive>
        <manifest>
          <addClasspath>true</addClasspath>
          <mainClass>com.mycompany.package.MainClass</mainClass>
        </manifest>
      </archive>
    </configuration>
  </plugin>
  <plugin>
    <artifactId>maven-assembly-plugin</artifactId>
    <configuration>
      <descriptorRefs>
        <descriptorRef>jar-with-dependencies</descriptorRef>
      </descriptorRefs>
      <archive>
        <manifest>
          <mainClass>com.mycompany.package.MainClass</mainClass>
        </manifest>
      </archive>
    </configuration>
    <executions>
      <execution>
        <id>make-my-jar-with-dependencies</id>
        <phase>package</phase>
        <goals>
          <goal>single</goal>
        </goals>
      </execution>
    </executions>
  </plugin>
</plugins>
</build>

Ensuite, vous devez basculer via la console vers le répertoire, où se trouve le pom.xml. Ensuite, vous devez exécuter mvn assembly: single , puis votre fichier JAR exécutable avec les dépendances sera, espérons-le, construit. Vous pouvez le vérifier lorsque vous passez au répertoire de sortie (cible) avec cd ./target et que vous démarrez votre jar avec une commande similaire à java -jar mavenproject1-1.0-SNAPSHOT-jar-with-dependencies.jar .

J'ai testé cela avec Apache Maven 3.0.3 .

Benny Neugebauer
la source
13

J'ai parcouru chacune de ces réponses en cherchant à créer un gros fichier exécutable contenant toutes les dépendances et aucune ne fonctionnait correctement. La réponse est le plugin d'ombre, c'est très simple et direct.

    <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-shade-plugin</artifactId>
      <version>2.3</version>
      <executions>
         <!-- Run shade goal on package phase -->
        <execution>
        <phase>package</phase>
        <goals>
            <goal>shade</goal>
        </goals>
        <configuration>
          <transformers>
             <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                <mainClass>path.to.MainClass</mainClass>
             </transformer>
          </transformers>
        </configuration>
          </execution>
      </executions>
    </plugin>

N'oubliez pas que vos dépendances doivent avoir une portée de compilation ou d'exécution pour que cela fonctionne correctement.

Cet exemple vient de mkyong.com

dsutherland
la source
Comme je l'ai résolu, cela vous dérangerait de mettre à jour votre avis. Je n'avais pas pris en compte vos pensées avant de poster et j'ai rapidement
corrigé
2
L' pluginélément entre en pom.xmldessous build/plugins.
isapir
12

Vous pouvez combiner le maven-shade-pluginet maven-jar-plugin.

  • le maven-shade-plugin packs vos classes et toutes les dépendances dans un seul fichier jar.
  • Configurez le maven-jar-pluginpour spécifier la classe principale de votre fichier exécutable (voir Configurer le chemin de classe , chapitre "Créer le fichier exécutable").

Exemple de configuration POM pour maven-jar-plugin:

        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-jar-plugin</artifactId>
            <version>2.3.2</version>
            <configuration>
                <archive>
                    <manifest>
                        <addClasspath>true</addClasspath>
                        <mainClass>com.example.MyMainClass</mainClass>
                    </manifest>
                </archive>
            </configuration>
        </plugin>

Enfin, créez le fichier exécutable en appelant:

mvn clean package shade:shade
Oliver
la source
3
Le plugin Shade a maintenant le moyen de spécifier l'entrée de classe principale dans le manifeste: maven.apache.org/plugins/maven-shade-plugin/examples/…
Chadwick
9

Ken Liu a raison à mon avis. Le plugin de dépendance maven vous permet d'étendre toutes les dépendances, que vous pouvez ensuite traiter comme des ressources. Cela vous permet de les inclure dans l' artefact principal . L'utilisation du plugin d'assemblage crée un artefact secondaire qui peut être difficile à modifier - dans mon cas, je voulais ajouter des entrées de manifeste personnalisées. Mon pom a fini par:

<project>
 ...
 <build>
  <plugins>
   <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-dependency-plugin</artifactId>
    <executions>
     <execution>
      <id>unpack-dependencies</id>
      <phase>package</phase>
      <goals>
       <goal>unpack-dependencies</goal>
      </goals>
     </execution>
    </executions>
   </plugin>
  </plugins>
  ...
  <resources>
   <resource>
    <directory>${basedir}/target/dependency</directory>
    <targetPath>/</targetPath>
   </resource>
  </resources>
 </build>
 ...
</project>
Matthew Franglen
la source
1
Vraiment sympa! Ne serait-il pas préférable d'utiliser la phase de génération de ressources pour le déballage?
nawroth
9

Ça devrait être comme ça:

<plugin>
    <artifactId>maven-dependency-plugin</artifactId>
    <executions>
        <execution>
            <id>unpack-dependencies</id>
            <phase>generate-resources</phase>
            <goals>
                <goal>unpack-dependencies</goal>
            </goals>
        </execution>
    </executions>
</plugin>

Le déballage doit être en phase de génération de ressources car, s'il est en phase de package, il ne sera pas inclus en tant que ressources. Essayez un emballage propre et vous verrez.

kac-ani
la source
7

Un problème avec la localisation du fichier d'assembly partagé avec maven-assembly-plugin-2.2.1?

Essayez d'utiliser le paramètre de configuration descriptorId au lieu des paramètres descriptors / descriptor ou descriptorRefs / descriptorRef.

Aucun d'eux ne fait ce dont vous avez besoin: recherchez le fichier sur classpath. Bien sûr, vous devez ajouter le package dans lequel l'assembly partagé réside dans le chemin de classe de maven-assembly-plugin (voir ci-dessous). Si vous utilisez Maven 2.x (pas Maven 3.x), vous devrez peut-être ajouter cette dépendance dans pom.xml parent le plus haut dans la section pluginManagement.

Voir ceci pour plus de détails.

Classe: org.apache.maven.plugin.assembly.io.DefaultAssemblyReader

Exemple:

        <!-- Use the assembly plugin to create a zip file of all our dependencies. -->
        <plugin>
            <artifactId>maven-assembly-plugin</artifactId>
            <version>2.2.1</version>
            <executions>
                <execution>
                    <id>make-assembly</id>
                    <phase>package</phase>
                    <goals>
                        <goal>single</goal>
                    </goals>
                    <configuration>
                        <descriptorId>assembly-zip-for-wid</descriptorId>
                    </configuration>
                </execution>
            </executions>
            <dependencies>
                <dependency>
                    <groupId>cz.ness.ct.ip.assemblies</groupId>
                    <artifactId>TEST_SharedAssemblyDescriptor</artifactId>
                    <version>1.0.0-SNAPSHOT</version>
                </dependency>
            </dependencies>
        </plugin>
Rostislav Stříbrný
la source
7

Pour résoudre ce problème, nous utiliserons le plug-in d'assemblage Maven qui créera le fichier JAR avec ses fichiers JAR de dépendance dans un seul fichier JAR exécutable. Ajoutez simplement la configuration du plugin ci-dessous dans votre fichier pom.xml.

<build>
   <pluginManagement>
      <plugins>
         <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-assembly-plugin</artifactId>
            <configuration>
               <archive>
                  <manifest>
                     <addClasspath>true</addClasspath>
                     <mainClass>com.your.package.MainClass</mainClass>
                  </manifest>
               </archive>
               <descriptorRefs>
                  <descriptorRef>jar-with-dependencies</descriptorRef>
               </descriptorRefs>
            </configuration>
            <executions>
               <execution>
                  <id>make-my-jar-with-dependencies</id>
                  <phase>package</phase>
                  <goals>
                     <goal>single</goal>
                  </goals>
               </execution>
            </executions>
         </plugin>
      </plugins>
   </pluginManagement>
</build>

Après cela, n'oubliez pas d'exécuter l'outil MAVEN avec cette commande mvn clean compile assembly: single

http://jkoder.com/maven-creating-a-jar-together-with-its-dependency-jars-into-a-single-executable-jar-file/

Anoop Rai
la source
5

Je ne répondrai pas directement à la question car d'autres l'ont déjà fait auparavant, mais je me demande vraiment si c'est une bonne idée d'incorporer toutes les dépendances dans le pot du projet lui-même.

Je vois le point (facilité de déploiement / utilisation) mais cela dépend du cas d'utilisation de votre projet (et il peut y avoir des alternatives (voir ci-dessous)).

Si vous l'utilisez de manière totalement autonome, pourquoi pas.

Mais si vous utilisez votre projet dans d'autres contextes (comme dans une webapp, ou déposé dans un dossier où se trouvent d'autres pots), vous pouvez avoir des doublons de pots dans votre chemin de classe (ceux du dossier, celui des pots). Peut-être pas un accord d'enchère, mais j'évite généralement cela.

Une bonne alternative:

  • déployez votre application au format .zip / .war: l'archive contient le pot de votre projet et tous les pots dépendants;
  • utiliser un mécanisme de chargeur de classe dynamique (voir Spring, ou vous pouvez facilement le faire vous-même) pour avoir un seul point d'entrée de votre projet (une seule classe pour commencer - voir le mécanisme du manifeste sur une autre réponse), qui ajoutera (dynamiquement) à la chemin de classe actuel tous les autres pots nécessaires.

Comme ça, avec au final juste un manifeste et un "chargeur de classe dynamique spécial principal", vous pouvez démarrer votre projet avec:

java -jar ProjectMainJar.jar com.stackoverflow.projectName.MainDynamicClassLoaderClass
SRG
la source
1
Comment mettre le pot du projet et tous les pots dépendants dans une archive alors?
4

Pour créer un fichier JAR exécutable à partir de la ligne de commande elle-même, exécutez simplement la commande ci-dessous à partir du chemin du projet:

mvn assembly:assembly
Mayank
la source
3
Je pense que vous avez encore besoin de faire des choses dans le pom.xmlcas contraire Error reading assemblies: No assembly descriptors found.. C'est ce qui m'arrive de toute façon.
Sridhar Sarnobat, le
3

C'est le meilleur moyen que j'ai trouvé:

  <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-jar-plugin</artifactId>
    <version>2.4</version>
    <configuration>
      <archive>
        <manifest>
        <addClasspath>true</addClasspath>
        <mainClass>com.myDomain.etc.MainClassName</mainClass>
        <classpathPrefix>dependency-jars/</classpathPrefix>
        </manifest>
      </archive>
    </configuration>
  </plugin>
  <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-dependency-plugin</artifactId>
    <version>2.5.1</version>
    <executions>
      <execution>
        <id>copy-dependencies</id>
        <phase>package</phase>
        <goals>
            <goal>copy-dependencies</goal>
        </goals>
        <configuration>
            <outputDirectory>
               ${project.build.directory}/dependency-jars/
            </outputDirectory>
        </configuration>
      </execution>
    </executions>
  </plugin>

Avec cette configuration, toutes les dépendances seront situées dans /dependency-jars. Mon application n'a pas de Mainclasse, juste des contextes, mais l'une de mes dépendances a une Mainclasse ( com.myDomain.etc.MainClassName) qui démarre le serveur JMX et reçoit un startou un stopparamètre. Donc, avec cela, j'ai pu démarrer mon application comme ceci:

java -jar ./lib/TestApp-1.0-SNAPSHOT.jar start

J'attends que ce soit utile pour vous tous.

EliuX
la source
3

J'ai comparé les plugins d'arbre mentionnés dans cet article. J'ai généré 2 pots et un répertoire avec tous les pots. J'ai comparé les résultats et le plugin maven-shadow est certainement le meilleur. Mon défi était que j'avais plusieurs ressources de printemps qui devaient être fusionnées, ainsi que des services jax-rs et JDBC. Ils ont tous été fusionnés correctement par le plugin d'ombre en comparaison avec le plugin maven-assembly-plugin. Dans ce cas, le ressort échouera, sauf si vous les copiez dans votre propre dossier de ressources et les fusionnez manuellement une fois. Les deux plugins produisent l'arborescence de dépendances correcte. J'ai eu plusieurs étendues comme tester, fournir, compiler, etc. le test et fourni ont été ignorés par les deux plugins. Ils ont tous deux produit le même manifeste, mais j'ai pu consolider les licences avec le plugin d'ombre à l'aide de leur transformateur. Avec le plugin maven-dependency, bien sûr que vous ne le faites pas t ont ces problèmes car les pots ne sont pas extraits. Mais comme certains l'ont souligné, vous devez transporter un ou plusieurs fichiers supplémentaires pour fonctionner correctement. Voici un aperçu du fichier pom.xml

            <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-dependency-plugin</artifactId>
            <executions>
                <execution>
                    <id>copy-dependencies</id>
                    <phase>prepare-package</phase>
                    <goals>
                        <goal>copy-dependencies</goal>
                    </goals>
                    <configuration>
                        <outputDirectory>${project.build.directory}/lib</outputDirectory>
                        <includeScope>compile</includeScope>
                        <excludeTransitive>true</excludeTransitive>
                        <overWriteReleases>false</overWriteReleases>
                        <overWriteSnapshots>false</overWriteSnapshots>
                        <overWriteIfNewer>true</overWriteIfNewer>
                    </configuration>
                </execution>
            </executions>
        </plugin>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-assembly-plugin</artifactId>
            <version>2.6</version>
            <configuration>
                <archive>
                    <manifest>
                        <addClasspath>true</addClasspath>
                        <mainClass>com.rbccm.itf.cdd.poller.landingzone.LandingZonePoller</mainClass>
                    </manifest>
                </archive>
                <descriptorRefs>
                    <descriptorRef>jar-with-dependencies</descriptorRef>
                </descriptorRefs>
            </configuration>
            <executions>
                <execution>
                    <id>make-my-jar-with-dependencies</id>
                    <phase>package</phase>
                    <goals>
                        <goal>single</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-shade-plugin</artifactId>
            <version>2.4.3</version>
            <configuration>
                <shadedArtifactAttached>false</shadedArtifactAttached>
                <keepDependenciesWithProvidedScope>false</keepDependenciesWithProvidedScope>
                <transformers>
                    <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
                        <resource>META-INF/services/javax.ws.rs.ext.Providers</resource>
                    </transformer>
                    <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
                        <resource>META-INF/spring.factories</resource>
                    </transformer>
                    <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
                        <resource>META-INF/spring.handlers</resource>
                    </transformer>
                    <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
                        <resource>META-INF/spring.schemas</resource>
                    </transformer>
                    <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
                        <resource>META-INF/spring.tooling</resource>
                    </transformer>
                    <transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
                    <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"/>
                    <transformer implementation="org.apache.maven.plugins.shade.resource.ApacheLicenseResourceTransformer">
                    </transformer>
                </transformers>
            </configuration>
            <executions>
                <execution>
                    <goals>
                        <goal>shade</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
Fabio
la source
2

Quelque chose qui a fonctionné pour moi était:

  <plugin>
    <artifactId>maven-dependency-plugin</artifactId>
    <executions>
      <execution>
        <id>unpack-dependencies</id>
        <phase>prepare-package</phase>
        <goals>
          <goal>unpack-dependencies</goal>
        </goals>
        <configuration>
          <outputDirectory>${project.build.directory}/classes</outputDirectory>
        </configuration>
      </execution>

    </executions>
  </plugin>


  <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-jar-plugin</artifactId>
    <executions>
      <execution>
        <id>unpack-dependencies</id>
        <phase>package</phase>
      </execution>
    </executions>
    <configuration>
      <archive>
        <manifest>
          <addClasspath>true</addClasspath>
          <classpathPrefix>lib/</classpathPrefix>
          <mainClass>SimpleKeyLogger</mainClass>
        </manifest>
      </archive>
    </configuration>
  </plugin>

J'ai eu un cas extraordinaire parce que ma dépendance était un système:

<dependency>
  ..
  <scope>system</scope>
  <systemPath>${project.basedir}/lib/myjar.jar</systemPath>
</dependency>

J'ai changé le code fourni par @ user189057 avec des changements: 1) le plugin maven-dependency est exécuté dans la phase "prepare-package" 2) J'extrais directement les classes décompressées vers "target / classes"

fascynacja
la source
2

J'ai essayé la réponse la plus votée ici et j'ai pu obtenir le pot exécutable. Mais le programme ne s'est pas exécuté correctement. Je ne connais pas la raison. Quand j'essaye de fuirEclipse , j'obtiens un résultat différent, mais lorsque j'exécute le pot à partir de la ligne de commande, j'obtiens un résultat différent (il se bloque avec une erreur d'exécution spécifique au programme).

J'avais une exigence similaire à celle de l'OP juste que j'avais trop de dépendances (Maven) pour mon projet. Heureusement, la seule solution qui a fonctionné pour moi était celle de l'utilisation Eclipse. Très simple et très simple. Ce n'est pas une solution à l'OP mais c'est une solution pour quelqu'un qui a une exigence similaire mais avec de nombreuses dépendances Maven,

1) Cliquez avec le bouton droit sur votre dossier de projet (dans Eclipse) et sélectionnez Export

2) Sélectionnez ensuite Java->Runnable Jar

3) Il vous sera demandé de choisir l'emplacement du fichier jar

4) Enfin, sélectionnez la classe qui a la méthode Main que vous souhaitez exécuter et choisissez Package dependencies with the Jar fileet cliquez surFinish

Rocky Inde
la source
2

Cela pourrait également être une option, vous pourrez créer votre fichier jar

<build>
    <plugins>
        <plugin>
            <!-- Build an executable JAR -->
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-jar-plugin</artifactId>
            <version>2.4</version>
            <configuration>
                <archive>
                    <manifest>
                        <addClasspath>true</addClasspath>
                        <classpathPrefix>lib/</classpathPrefix>
                        <mainClass>WordListDriver</mainClass>
                    </manifest>
                </archive>
            </configuration>
        </plugin>
    </plugins>
</build>
salmanbw
la source
2

Pour tous ceux qui recherchent des options pour exclure des dépendances spécifiques de l'uber-jar, voici une solution qui a fonctionné pour moi:

<project...>
<dependencies>
        <dependency>
            <groupId>org.apache.spark</groupId>
            <artifactId>spark-core_2.11</artifactId>
            <version>1.6.1</version>
            <scope>provided</scope> <=============
        </dependency>
</dependencies>
<build>
        <plugins>
            <plugin>
                <artifactId>maven-assembly-plugin</artifactId>
                <configuration>
                    <descriptorRefs>
                        <descriptorRef>jar-with-dependencies</descriptorRef>
                    </descriptorRefs>
                    <archive>
                        <manifest>
                            <mainClass>...</mainClass>
                        </manifest>
                    </archive>
                </configuration>
                <executions>
                    <execution>
                        <id>make-assembly</id>
                        <phase>package</phase>
                        <goals>
                            <goal>single</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

Ce n'est donc pas une configuration du mvn-assembly-plugin mais une propriété de la dépendance.

Paul Bormans
la source
2

Il y a déjà des millions de réponses, je voulais ajouter que vous n'avez pas besoin <mainClass>si vous n'avez pas besoin d'ajouter entryPoint à votre application. Par exemple, les API peuvent ne pas avoir nécessairement de mainméthode.

configuration du plugin maven

  <build>
    <finalName>log-enrichment</finalName>
    <plugins>
      <plugin>
        <artifactId>maven-assembly-plugin</artifactId>
        <configuration>
          <descriptorRefs>
            <descriptorRef>jar-with-dependencies</descriptorRef>
          </descriptorRefs>
        </configuration>
      </plugin>
    </plugins>
  </build>

construire

mvn clean compile assembly:single

Vérifier

ll target/
total 35100
drwxrwx--- 1 root vboxsf     4096 Sep 29 16:25 ./
drwxrwx--- 1 root vboxsf     4096 Sep 29 16:25 ../
drwxrwx--- 1 root vboxsf        0 Sep 29 16:08 archive-tmp/
drwxrwx--- 1 root vboxsf        0 Sep 29 16:25 classes/
drwxrwx--- 1 root vboxsf        0 Sep 29 16:25 generated-sources/
drwxrwx--- 1 root vboxsf        0 Sep 29 16:25 generated-test-sources/
-rwxrwx--- 1 root vboxsf 35929841 Sep 29 16:10 log-enrichment-jar-with-dependencies.jar*
drwxrwx--- 1 root vboxsf        0 Sep 29 16:08 maven-status/
Prayagupd
la source
2

Ajoutez à pom.xml:

  <dependency>
            <groupId>com.jolira</groupId>
            <artifactId>onejar-maven-plugin</artifactId>
            <version>1.4.4</version>
  </dependency>

et

<plugin>
       <groupId>com.jolira</groupId>
       <artifactId>onejar-maven-plugin</artifactId>
       <version>1.4.4</version>
       <executions>
              <execution>
                     <goals>
                         <goal>one-jar</goal>
                     </goals>
              </execution>
       </executions>
</plugin>

C'est ça. Le prochain paquet mvn créera également un gros pot en plus, y compris tous les pots de dépendance.

Aydin K.
la source
1

Le plugin maven-assembly-plug a très bien fonctionné pour moi. J'ai passé des heures avec le plugin maven-dependency et je n'ai pas pu le faire fonctionner. La raison principale était que je devais définir explicitement dans la section de configuration les éléments d'artefact qui devraient être inclus comme cela est décrit dans la documentation . Il y a un exemple pour les cas où vous souhaitez l'utiliser comme:, mvn dependency:copyoù il n'y a pas d'artefactItems inclus mais cela ne fonctionne pas.

Chris
la source
1

Ce billet de blog montre une autre approche avec la combinaison des plugins maven-jar et maven-assembly. Avec le xml de configuration d'assembly du billet de blog, il peut également être contrôlé si les dépendances seront développées ou simplement collectées dans un dossier et référencées par une entrée classpath dans le manifeste:

La solution idéale consiste à inclure les fichiers jars dans un dossier lib et le fichier manifest.mf du fichier jar principal inclut tous les fichiers jars dans classpath.

Et c'est exactement celui-là qui est décrit ici: https://caffebig.wordpress.com/2013/04/05/executable-jar-file-with-dependent-jars-using-maven/

Jan Ziegler
la source
0
<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-assembly-plugin</artifactId>
            <version>2.4.1</version>
            <configuration>
                <!-- get all project dependencies -->
                <descriptorRefs>
                    <descriptorRef>jar-with-dependencies</descriptorRef>
                </descriptorRefs>
            </configuration>
            <executions>
                <execution>
                    <id>make-assembly</id>
                    <!-- bind to the packaging phase -->
                    <phase>package</phase>
                    <goals>
                        <goal>single</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>
Shang Gao
la source
1
Besoin d'un peu plus d'explications à ce sujet; ces commentaires sont-ils simplement de la documentation, ou faut-il que des options supplémentaires soient placées à l'emplacement de ces commentaires?
Mark Stewart
-2

D'accord, c'est donc ma solution. Je sais qu'il n'utilise pas le fichier pom.xml. Mais j'ai eu le problème de compilation et d'exécution de mon programme sur Netbeans mais il a échoué lorsque j'ai essayé Java -jar MyJarFile.jar. Maintenant, je ne comprends pas bien Maven et je pense que cela a eu du mal à obtenir que Netbeans 8.0.2 inclue mon fichier jar dans une bibliothèque pour les mettre dans un fichier jar. Je pensais à la façon dont j'utilisais les fichiers jar sans Maven dans Eclipse.

C'est Maven qui peut compiler toutes les dépendances et tous les plugins. Pas Netbeans. (Si vous pouvez obtenir Netbeans et pouvoir utiliser java .jar pour ce faire, dites-moi comment (^. ^) V)

[Résolu - pour Linux] en ouvrant un terminal.

alors

cd /MyRootDirectoryForMyProject

Prochain

mvn org.apache.maven.plugins:maven-compiler-plugin:compile

Prochain

mvn install

Cela créera un fichier jar dans le répertoire cible.

MyJarFile-1.0-jar-with-dependencies.jar

Maintenant

cd target

(Vous devrez peut - être exécuter: chmod +x MyJarFile-1.0-jar-with-dependencies.jar)

et enfin

java -jar MyJarFile-1.0-jar-with-dependencies.jar

S'il te plait regarde

https://cwiki.apache.org/confluence/display/MAVEN/LifecyclePhaseNotFoundException

Je publierai cette solution dans quelques autres pages avec un problème similaire. J'espère pouvoir sauver quelqu'un d'une semaine de frustration.

mycowan
la source
2
Essayez d'ouvrir le projet Maven que vous avez créé avec Netbeans. La règle de base de Netbeans est toujours de créer un projet Maven et jamais une 'application Java'. Ajouter un plugin maven-shadow comme l'une des réponses. Fonctionne comme un charme.
rjdkolb