Skip navigation

Vous cherchez à créer un jar exécutable de votre projet Maven alors cet article devrait vous aider ! Nous verrons dans un premier temps comment utiliser le plugin Maven Assembly pour réaliser le jar exécutable. Afin de pousser un peu le packaging de notre application, je vous expliquerai ensuite comment automatiquement inclure ce jar dans un zip ou dans un tar.gz.

Notre application a une architecture très classique :

  • src
    • main
      • java
        • fr.romaingervais.HelloWord.java (classe main à exécuter)
      • resources
    • test
      • java
      • resources
  • target
  • pom.xml

Application sans test… comme je l’ai dit très classique :) (Je rigole bien évidemment) Le pom.xml ressemble tout simplement à ça actuellement :

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
			xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
      <modelVersion>4.0.0</modelVersion>
      <groupId>romain-gervais</groupId>
      <artifactId>helloworld</artifactId>
      <version>0.0.1-SNAPSHOT</version>
      <packaging>jar</packagin>
</project>

Le fait de préciser <packaging>jar</packagin> n’indique pas que Maven va créer un jar exécutable avec toute ses dépendances. Ce jar ne contiendra que les classes compilées de notre projet et ne sera pas exécutable. Je n'ai aucune dépendance dans mon POM vers d'autres projets Maven afin d'alléger l'article, mais si votre projet contient des dépendances, elles seront bien incluses dans le jar exécutable avec la méthode que je propose.

Ajoutons maintenant le plugin maven assembly qui va nous permettre de créer un jar exécutable,le POM devient :

<plugins>
<!-- packaging de l'application -->
	<plugin>
		<!-- NOTE: We don't need a groupId specification because the group is org.apache.maven.plugins ...which is assumed by default. -->
		<artifactId>maven-assembly-plugin</artifactId>
		<version>2.3</version>
		<configuration>
			  <descriptors>
<descriptor>src/main/assembly/jar.xml</descriptor>
			  </descriptors>
			  <archive>
				   <manifest>
						<mainClass>fr.romaingervais.HelloWorld</mainClass>
				   </manifest>
			  </archive>
		</configuration>
		<executions>
			  <execution>
				   <id>executable</id>
				   <phase>package</phase>
				   <goals>
						<goal>single</goal>
				   </goals>
			 </execution>
		</executions>
     </plugin>
</plugins>

On indique donc ici la classe main (<mainClass>), que notre jar sera créé lors de la phase « packaging » de Maven(<phase> + <goals>), ainsi qu’un fichier « descriptor »(<descriptor>). Ce fichier va nous permettre de préciser plus d’option sur la conception de notre jar, voici son contenu :

<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
      <id>executable</id>
      <formats>
            <format>jar</format>
      </formats>
      <includeBaseDirectory>false</includeBaseDirectory>
      <dependencySets>
            <dependencySet>
                  <!-- décompresse les dépendances avant de les inclure dans le jar exécutable -->
                  <unpack>true</unpack>
                  <scope>runtime</scope>
                  <useProjectArtifact>false</useProjectArtifact>
            </dependencySet>
      </dependencySets>
      <fileSets>
            <fileSet>
                  <directory>${project.build.outputDirectory}</directory>
                  <outputDirectory></outputDirectory>
            </fileSet>
      </fileSets>
</assembly>

Je ne vais pas détailler tous les attributs, mais sachez que chacune des options est définie sur le site officiel. Dans les grandes lignes tout de même on retrouve l’id qui est égal à <execution><id> dans le POM, le format, les fichiers à traiter (<fileSet><directory>), le répertoire de sortie (<fileSet><outputDirectory>). Veuillez noter qu’il est possible d’inclure ou d’exclure des fichiers (<fileSet><includes> et <fileSet><excludes>) ; Comme nous n’avons rien précisé ici tout est inclus.

En lançant la commande maven install (ou simplement maven package si votre application est déjà installée) vous obtiendrez donc dans le dossier "/target" un jar nommé "helloworld-0.0.1-SNAPSHOT-executable.jar". Il ne vous reste plus qu’à exécuter ce jar comme vous en avez l’habitude :

java -jar helloworld-0.0.1-SNAPSHOT-executable.jar

Vous avez maintenant toutes les clés pour créer un jar exécutable avec Maven. Pour ceux qui souhaiteraient approfondir un peu plus je vais vous montrer comment créer un zip contenant le jar et un fichier exécutable permettant de lancer le jar. Pour complexifier le problème partons du principe que nous devons livrer notre application aussi bien à destination de windowsiens que de linuxiens. Nous allons donc créer un zip avec un lanceur.bat, et un tar.gz avec un lanceur.sh

Il nous faut nous servir des profils Maven pour arriver à nos fins (du moins c’est ma méthode, il en existe peut-être d’autres) .  Notre POM ressemble maintenant à ceci :

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
      <modelVersion>4.0.0</modelVersion>
      <groupId>romain-gervais</groupId>
      <artifactId>helloworld</artifactId>
      <version>0.0.1-SNAPSHOT</version>
      <packaging>jar</packaging>

      <dependencyManagement>
            <dependencies>
                  <dependency>
                        <groupId>org.apache.maven.plugins</groupId>
                        <artifactId>maven-assembly-plugin</artifactId>
                        <version>2.3</version>
                  </dependency>
            </dependencies>
      </dependencyManagement>

      <build>
            <!-- Plugin pour compiler le code JAVA -->
            <plugins>

                  <!-- packaging de l'application -->
                  <plugin>
                        <!-- NOTE: We don't need a groupId specification because the group is
                             org.apache.maven.plugins ...which is assumed by default. -->
                        <artifactId>maven-assembly-plugin</artifactId>
                        <executions>
                             <execution>
                                   <id>executable</id>
                                   <phase>package</phase>
                                   <goals>
                                         <goal>single</goal>
                                   </goals>
                                   <configuration>
                                         <descriptors>
                                               <descriptor>src/main/assembly/jar.xml</descriptor>
                                         </descriptors>
                                         <archive>
                                               <manifest>
                                                     <mainClass>fr.romaingervais.HelloWorld</mainClass>
                                               </manifest>
                                         </archive>
                                   </configuration>
                             </execution>
                        </executions>
                  </plugin>
            </plugins>
      </build>
      <profiles>
            <profile>
                  <id>linux</id>
                  <activation>
                        <activeByDefault>false</activeByDefault>
                  </activation>
                  <build>
                        <plugins>
                             <plugin>
                                   <artifactId>maven-assembly-plugin</artifactId>
                                   <executions>
                                         <execution>
                                               <id>tar-gz</id>
                                               <phase>install</phase>
                                               <goals>
                                                     <goal>single</goal>
                                               </goals>
                                               <configuration>
                                                     <descriptors>
                                                           <descriptor>src/main/assembly/tar.gz.xml</descriptor>
                                                     </descriptors>
                                               </configuration>
                                         </execution>
                                   </executions>
                             </plugin>
                        </plugins>
                  </build>
            </profile>
            <profile>
                  <id>windows</id>
                  <activation>
                        <activeByDefault>false</activeByDefault>
                  </activation>
                  <build>
                        <plugins>
                             <plugin>
                                   <artifactId>maven-assembly-plugin</artifactId>
                                   <executions>
                                         <execution>
                                               <id>zip</id>
                                               <phase>install</phase>
                                               <goals>
                                                     <goal>single</goal>
                                               </goals>
                                               <configuration>
                                                     <descriptors>
                                                           <descriptor>src/main/assembly/zip.xml</descriptor>
                                                     </descriptors>
                                               </configuration>
                                         </execution>
                                   </executions>
                             </plugin>
                        </plugins>
                  </build>
            </profile>
      </profiles>
</project>

On voit bien apparaitre les deux profils avec chacun sa configuration du plugin "maven assembly". On construit les deux archives dans la phase d’installation car le jar doit déjà être construit (durant la phase package) pour être inclus dans le zip ou le tar.gz. Voici maintenant les deux assembly associés à chaque profil :

<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
      <id>tar-gz</id>
      <formats>
            <format>tar.gz</format>
      </formats>
      <includeBaseDirectory>false</includeBaseDirectory>
      <fileSets>
            <fileSet>
                  <directory>target</directory>
                  <includes>
                        <include>*-executable.jar</include>
                  </includes>
                  <outputDirectory>/</outputDirectory>
            </fileSet>
            <fileSet>
                  <directory>src/main/script</directory>
                  <filtered>true</filtered>
                  <fileMode>0777</fileMode>
                  <includes>
                        <include>lanceur.sh</include>
                  </includes>
                  <outputDirectory>/</outputDirectory>
            </fileSet>
      </fileSets>
</assembly>
<assembly
      xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
      <id>zip</id>
      <formats>
            <format>zip</format>
      </formats>
      <includeBaseDirectory>false</includeBaseDirectory>
      <fileSets>
            <fileSet>
                  <directory>target</directory>
                  <includes>
                        <include>*-executable.jar</include>
                  </includes>
                  <outputDirectory>/</outputDirectory>
            </fileSet>
            <fileSet>
                  <directory>src/main/script</directory>
                  <filtered>true</filtered>
                  <includes>
                        <include>lanceur.bat</include>
                  </includes>
                  <outputDirectory>/</outputDirectory>
            </fileSet>
      </fileSets>
</assembly>

Vous remarquez qu’on donne les droits d’execution au fichier lanceur.sh (à adapter selon vos besoin, 0777 est fortement déconseillé en production). Vous pouvez aussi voir l’option <filtered>true</filtered> qui permet de préciser que les fichiers lanceur.bat et lanceur.sh sont des ressources à filtrer. Ceci va permettre de placer des variables dans ces fichiers. Maven remplacera ensuite ces variables par leur valeur à la compilation.

Voici le contenu du lanceur.bat :

java -jar ${project.artifactId}-${project.version}-executable.jar

Et du lanceur.sh :

#!/bin/bash

java -jar ${project.artifactId}-${project.version}-executable.jar

Vous pouvez maintenant lancer la commade mvn install -Plinux,windows. Vous créerez ainsi le jar exécutable ainsi que les deux archives à destination de Linux et Windows.