« Votre application ne fonctionne que dans l'IDE ? Il est temps de changer ça ! »
\n\nSi vous avez déjà programmé en Java, vous connaissez sûrement cette situation : vous montrez fièrement votre nouveau projet à un ami, vous le lancez dans IntelliJ IDEA ou Eclipse — tout fonctionne parfaitement. Mais dès que vous transmettez ce projet à un collègue ou essayez de l'exécuter en ligne de commande, vous êtes accueilli par une ClassNotFoundException ou une NoClassDefFoundError. Ça vous parle ?
\n\nDans la plupart des cours et tutoriels, on apprend à créer un fichier JAR avec Maven, mais on oublie souvent un détail crucial : où passent les dépendances ? Un fichier JAR standard ne contient que votre code, tandis que toutes les bibliothèques (comme Apache Commons, Jackson, JUnit) restent à l'extérieur. C'est pourquoi des millions de développeurs Java posent cette question sur Stack Overflow : « How can I create an executable/runnable JAR with dependencies using Maven? »
\n\nDans cet article, nous allons explorer plusieurs méthodes éprouvées pour créer un JAR exécutable avec dépendances à l'aide de Maven. Vous apprendrez à configurer maven-assembly-plugin, maven-shade-plugin, et même comment cela fonctionne avec Spring Boot. C'est parti !
\n\nPourquoi un JAR standard ne fonctionne-t-il pas ?
\n\nFaisons une petite expérience. Imaginez que vous avez une application qui analyse du JSON avec la bibliothèque Jackson. Vous créez un JAR standard avec la commande mvn package, puis vous essayez de l'exécuter :
java -jar my-app.jar\n\nEt vous obtenez quelque chose comme :
\n\nException in thread "main" java.lang.NoClassDefFoundError: com/fasterxml/jackson/databind/ObjectMapper\n\nPourquoi cela arrive-t-il ? Parce que Maven, par défaut, ne regroupe que votre code compilé (les classes du dossier src/main/java). Toutes les dépendances que vous avez déclarées dans pom.xml restent dans le dépôt local de Maven (~/.m2/repository). Lorsque vous lancez le JAR, la JVM ne sait pas où trouver ces bibliothèques et génère une erreur.
La solution est de créer un fat JAR (JAR épais) ou uber JAR, qui contient non seulement vos classes, mais aussi toutes les dépendances nécessaires. C'est exactement à cela que servent les plugins Maven spécialisés.
\n\nMéthode 1 : maven-assembly-plugin (simple et fiable)
\n\nLa méthode la plus populaire et la plus simple consiste à utiliser maven-assembly-plugin. Il crée un JAR dans lequel toutes les dépendances sont décompressées et fusionnées avec vos classes. Configurons-le.
\n\nAjoutez le code suivant à votre pom.xml dans la section <build><plugins> :
<plugin>\n <groupId>org.apache.maven.plugins</groupId>\n <artifactId>maven-assembly-plugin</artifactId>\n <version>3.6.0</version>\n <configuration>\n <descriptorRefs>\n <descriptorRef>jar-with-dependencies</descriptorRef>\n </descriptorRefs>\n <archive>\n <manifest>\n <mainClass>com.example.Main</mainClass>\n </manifest>\n </archive>\n </configuration>\n <executions>\n <execution>\n <id>make-assembly</id>\n <phase>package</phase>\n <goals>\n <goal>single</goal>\n </goals>\n </execution>\n </executions>\n</plugin>\n\nImportant : remplacez com.example.Main par le nom complet de votre classe contenant la méthode main.
Construisez maintenant le projet avec la commande :
\n\nmvn clean package\n\nDans le dossier target, deux fichiers apparaîtront :
- \n
my-app.jar— le JAR standard \n my-app-jar-with-dependencies.jar— le JAR avec toutes les dépendances \n
Pour exécuter ce dernier, utilisez simplement :
\n\njava -jar target/my-app-jar-with-dependencies.jar\n\nEt voilà ! Votre application fonctionne désormais sans IDE, prête à être partagée.
\n\nMéthode 2 : maven-shade-plugin (pour les projets avancés)
\n\nLe maven-shade-plugin offre plus de contrôle. Il permet notamment de renommer les packages (shading) pour éviter les conflits de dépendances. C'est la solution idéale si vous utilisez plusieurs bibliothèques qui partagent les mêmes noms de classes.
\n\nAjoutez cette configuration dans votre pom.xml :
<plugin>\n <groupId>org.apache.maven.plugins</groupId>\n <artifactId>maven-shade-plugin</artifactId>\n <version>3.5.1</version>\n <configuration>\n <transformers>\n <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">\n <mainClass>com.example.Main</mainClass>\n </transformer>\n </transformers>\n </configuration>\n <executions>\n <execution>\n <phase>package</phase>\n <goals>\n <goal>shade</goal>\n </goals>\n </execution>\n </executions>\n</plugin>\n\nExécutez mvn clean package et vous obtiendrez un fichier nommé my-app-shaded.jar (ou original-my-app.jar pour la version sans dépendances).
Astuce : Si vous rencontrez des conflits entre dépendances, utilisez l'option <relocations> pour déplacer les packages problématiques vers un nouvel espace de noms.
Méthode 3 : Spring Boot Maven Plugin (pour les projets Spring)
\n\nSi vous utilisez Spring Boot, la création d'un JAR exécutable est encore plus simple. Le Spring Boot Maven Plugin intègre automatiquement toutes les dépendances et configure le point d'entrée.
\n\nAjoutez simplement ce plugin à votre pom.xml :
<plugin>\n <groupId>org.springframework.boot</groupId>\n <artifactId>spring-boot-maven-plugin</artifactId>\n <version>3.2.0</version>\n <executions>\n <execution>\n <goals>\n <goal>repackage</goal>\n </goals>\n </execution>\n </executions>\n</plugin>\n\nExécutez mvn clean package et vous obtiendrez un JAR prêt à l'emploi. Spring Boot s'occupe de tout : dépendances, manifeste, et même le chargement des ressources.
Comparatif des méthodes
\n\n| Plugin | \nAvantages | \nInconvénients | \n
|---|---|---|
| maven-assembly-plugin | \nSimple, fiable, idéal pour les débutants | \nPeut créer des conflits de fichiers (META-INF) | \n
| maven-shade-plugin | \nRenommage de packages, évite les conflits | \nConfiguration plus complexe | \n
| Spring Boot Maven Plugin | \nAutomatique, optimisé pour Spring | \nNécessite Spring Boot | \n
Dépannage des erreurs courantes
\n\nErreur : « No main manifest attribute »
\nSolution : Vérifiez que vous avez bien spécifié <mainClass> dans la configuration du plugin.
Erreur : « Class path contains multiple SLF4J bindings »
\nSolution : Utilisez maven-shade-plugin avec l'option <transformers> pour fusionner les fichiers de configuration.
Erreur : « ZipException: invalid LOC header »
\nSolution : Supprimez le dossier target et relancez la construction avec mvn clean package.
Conclusion
\n\nCréer un JAR exécutable avec toutes ses dépendances dans Maven n'est pas sorcier, une fois que l'on connaît les bons plugins. Que vous choisissiez maven-assembly-plugin pour sa simplicité, maven-shade-plugin pour sa flexibilité, ou Spring Boot Maven Plugin pour son automatisation, vous pouvez désormais partager vos applications Java sans craindre les erreurs de classe manquante.
\n\nEt vous, quelle méthode utilisez-vous ? Partagez votre expérience dans les commentaires !