Maven est un puissant outil de gestion de projet pour Java. Il simplifie diverses tâches essentielles telles que la compilation, la génération de documentation, la gestion des dépendances, l’intégration avec les systèmes de gestion de version du code source, la gestion des releases et la distribution des projets Java.
Les objets gérés par Maven, comme les bibliothèques Java, les modèles de projets, et les plugins Maven, sont appelés des artefacts. Chaque artefact est identifié par des coordonnées spécifiques, constituées de trois éléments principaux :
groupId : Identifie fonctionnellement un groupe d’artefacts.
artefactId : Identifie un artefact spécifique au sein du groupe.
version : Spécifie la version de l’artefact.
Pour les versions, il est recommandé de suivre une approche “sémantique” conformément aux principes du versionnage sémantique (semver).
Outil de gestion de projet pour Java
Simplifie : compilation, documentation, dépendances, versions, releases, distribution
Artefacts Maven:
Objets gérés (bibliothèques, modèles de projets, plugins)
Coordonnées : groupId (groupe), artefactId (identifiant), version (version)
Un projet Maven peut être créé à partir d’un archetype Maven, qui est un modèle de projet préconfiguré facilitant la création de projets conformes à certaines structures et pratiques standardisées.
Choix de l’Archetype
archetypeGroupId : Identifie le groupe auquel appartient l’archetype.
archetypeArtifactId : Identifie l’archetype spécifique à utiliser.
archetypeVersion : Spécifie la version de l’archetype.
Options du Projet
groupId : Identifie le groupe auquel le projet à créer appartient.
artifactId : Identifie le nouveau projet.
version : Spécifie la version initiale du projet.
Dans l’exemple ci-dessous l’archetype utilisé est un projet Java de base. Les options --no-transfer-progress, --batch-mode et --color always ne sont utiles que pour la génération non interactive.
On peut ensuite compiler le projet depuis l’intérieur du projet (le dossier contenant le fichier pom.xml). Les classes sont produites dans le sous-répertoire target/classes. Le programme peut être exécuté avec la commande java en ajoutant ce répertoire au classpath si aucune dépendance externe n’est nécessaire.
En pratique, il est conseillé de ne pas utiliser maven directement mais via un script standard: Le Maven Wrapper. C’est un outil essentiel pour les développeurs Java souhaitant garantir la cohérence des versions de Maven utilisées dans leurs projets. En ajoutant simplement un script (mvnw ou mvnw.cmd) à votre projet, le Maven Wrapper permet d’exécuter des commandes Maven avec une version spécifique, sans nécessiter une installation préalable de Maven sur chaque machine de développement. La création de ce script se fait via la commande mvn wrapper:wrapper.
[INFO] Scanning for projects...
[INFO]
[INFO] ---------------< fr.univtln.bruno.samples:MyMinimalApp >----------------
[INFO] Building MyMinimalApp 0.1.0-SNAPSHOT
[INFO] from pom.xml
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- resources:3.3.1:resources (default-resources) @ MyMinimalApp ---
[INFO] skip non existing resourceDirectory /home/jovyan/work/src/github/ebpro/notebook-java-maven/MyMinimalApp/src/main/resources
[INFO]
[INFO] --- compiler:3.13.0:compile (default-compile) @ MyMinimalApp ---
[INFO] Recompiling the module because of changed source code.
[INFO] Compiling 1 source file with javac [debug release 17] to target/classes
[INFO]
[INFO] --- resources:3.3.1:testResources (default-testResources) @ MyMinimalApp ---
[INFO] skip non existing resourceDirectory /home/jovyan/work/src/github/ebpro/notebook-java-maven/MyMinimalApp/src/test/resources
[INFO]
[INFO] --- compiler:3.13.0:testCompile (default-testCompile) @ MyMinimalApp ---
[INFO] Recompiling the module because of changed dependency.
[INFO] Compiling 1 source file with javac [debug release 17] to target/test-classes
[INFO]
[INFO] --- surefire:3.3.0:test (default-test) @ MyMinimalApp ---
[INFO] Using auto detected provider org.apache.maven.surefire.junitplatform.JUnitPlatformProvider
[INFO]
[INFO] -------------------------------------------------------
[INFO] T E S T S
[INFO] -------------------------------------------------------
[INFO] Running fr.univtln.bruno.samples.AppTest
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.062 s -- in fr.univtln.bruno.samples.AppTest
[INFO]
[INFO] Results:
[INFO]
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
[INFO]
[INFO]
[INFO] --- jar:3.4.2:jar (default-jar) @ MyMinimalApp ---
[INFO] Building jar: /home/jovyan/work/src/github/ebpro/notebook-java-maven/MyMinimalApp/target/MyMinimalApp-0.1.0-SNAPSHOT.jar
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1.772 s
[INFO] Finished at: 2024-12-05T09:37:42Z
[INFO] ------------------------------------------------------------------------
La plugin exec permet d’exécuter le projet courant en fixant autexec:java d’exécuter une classe Java en prenant en charge automatiquement le classpath y compris les dépendances indiquée dans pom.xml.
[INFO] Scanning for projects...
[INFO]
[INFO] ---------------< fr.univtln.bruno.samples:MyMinimalApp >----------------
[INFO] Building MyMinimalApp 0.1.0-SNAPSHOT
[INFO] from pom.xml
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- exec:3.5.0:java (default-cli) @ MyMinimalApp ---
Hello World!
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 0.355 s
[INFO] Finished at: 2024-12-05T09:37:43Z
[INFO] ------------------------------------------------------------------------
Le projet peut être paramétré en modifiant le fichier pom.xml. Il est possible de modifier le nom du projet, son URL et d’ajouter des métadonnées.
La construction du projet est contrôlée par des plugins paramétrés dans la section build/plugins.
Par exemple, il est possible de changer la version du code source acceptée pour ce projet et celle du bytecode java produit. Les évolution du langage et la machine virtuelle correspondent à des versions précises.
La commande javap permet d’explorer le byecode et d’afficher la version. D’après wikipedia les versions majeures sont :
Java SE 22 = 66 (0x42 hex)
Java SE 21 = 65 (0x41 hex)
Java SE 20 = 64 (0x40 hex)
Java SE 19 = 63 (0x3F hex)
Java SE 18 = 62 (0x3E hex)
Java SE 17 = 61 (0x3D hex)
Java SE 16 = 60 (0x3C hex)
Java SE 15 = 59 (0x3B hex)
Java SE 14 = 58 (0x3A hex)
Java SE 13 = 57 (0x39 hex)
Java SE 12 = 56 (0x38 hex)
Java SE 11 = 55 (0x37 hex)
Java SE 10 = 54 (0x36 hex)
Java SE 9 = 53 (0x35 hex)
Java SE 8 = 52 (0x34 hex)
Java SE 7 = 51 (0x33 hex)
Java SE 6.0 = 50 (0x32 hex)
Java SE 5.0 = 49 (0x31 hex)
JDK 1.4 = 48 (0x30 hex)
JDK 1.3 = 47 (0x2F hex)
JDK 1.2 = 46 (0x2E hex)
JDK 1.1 = 45 (0x2D hex)
Le modèle de projet utilisé fixe la version de Java à 17 (même si le compilateur est d’une version supérieur).
%%shellcd /home/jovyan/work/src/github/ebpro/notebook-java-maven/MyMinimalAppecho "Version de JDK installée: $(java --version|head -n 1)"echo "Version cible indiquée dans le pom.xml: $(grep '<maven.compiler.release>' pom.xml)"echo "Version du bytecode de la classe principale compilée :"javap -v -c target/classes/fr/univtln/bruno/samples/App.class| grep "major version"
Version de JDK installée: openjdk 21.0.5 2024-10-15 LTS
Version cible indiquée dans le pom.xml: <maven.compiler.release>17</maven.compiler.release>
Version du bytecode de la classe principale compilée :
major version: 61
Si l’on augmente la version du JDK cela ne change pas la version de bytecode produit.
%%shellcd /home/jovyan/work/src/github/ebpro/notebook-java-maven/MyMinimalAppsdk use java $(sdk list java|grep installed|cut -d '|'-f 6|tr -d ' '|grep "^23.*-tem")./mvnw --quiet packageecho "Version de JDK installée: $(java --version|head -n 1)"echo "Version cible indiquée dans le pom.xml: $(grep '<maven.compiler.release>' pom.xml)"echo "Version du bytecode de la classe principale compilée :"javap -v -c target/classes/fr/univtln/bruno/samples/App.class| grep "major version"
Using java version 23.0.1-tem in this shell.
Version de JDK installée: openjdk 23.0.1 2024-10-15
Version cible indiquée dans le pom.xml: <maven.compiler.release>17</maven.compiler.release>
Version du bytecode de la classe principale compilée :
major version: 61
Il faut modifier le pom.xml pour passer de la version 17 à la version 22 de Java (). Vérifier que celle du bytecode augmente.
%%shellcd /home/jovyan/work/src/github/ebpro/notebook-java-maven/MyMinimalAppsed -i 's/>17</>22</g' pom.xmlsdk use java $(sdk list java|grep installed|cut -d '|'-f 6|tr -d ' '|grep "^23.*-tem")./mvnw --quiet packageecho "Version de JDK installée: $(java --version|head -n 1)"echo "Version cible indiquée dans le pom.xml: $(grep '<maven.compiler.release>' pom.xml)"echo "Version du bytecode de la classe principale compilée :"javap -v -c target/classes/fr/univtln/bruno/samples/App.class| grep "major version"
Using java version 23.0.1-tem in this shell.
Version de JDK installée: openjdk 23.0.1 2024-10-15
Version cible indiquée dans le pom.xml: <maven.compiler.release>22</maven.compiler.release>
Version du bytecode de la classe principale compilée :
major version: 61
Utilisation avancée
Un projet java réel est souvent plus complexe, l’archetype non officiel suivant intégre les points les plus importants.
En utilisant le plugin shade, il est possible de produire des fichiers .jar qui incluent toutes les dépendances nécessaires. Ce type de fichier est appelé un fatjar ou uberjar. Il permet également de définir une classe principale par défaut pour rendre le jar “exécutable”. C’est l’approche traditionnelle pour livrer un exécutable Java.
Ce modèle inclut également des tests unitaires et des tests d’intégration dans la phase verify.
-rw-r--r-- 1 jovyan users 219K Dec 5 09:38 target/MyAppHelloWorld-0.1.0-SNAPSHOT-withdependencies.jar
-rw-r--r-- 1 jovyan users 5.3K Dec 5 09:38 target/MyAppHelloWorld-0.1.0-SNAPSHOT.jar
SLF4J(I): Connected with provider of type [ch.qos.logback.classic.spi.LogbackServiceProvider]
Livraison modulaire
L’approche moderne, bien que plus complexe, pour livrer un programme Java consiste à utiliser les modules introduits dans Java 9 avec l’outil jlink. jlink génère une version allégée du JRE (Java Runtime Environment) qui inclut seulement les composants requis par votre application. Le profil jlink intégre cela, ainsi, il n’est plus nécessaire d’installer de JRE sur la machine du client.
SLF4J(I): Connected with provider of type [ch.qos.logback.classic.spi.LogbackServiceProvider]
09:38:07.988 [main] INFO fr.univtln.bruno.samples.App -- Hello World!
Dépendances et versions
Les dépendances et plugins sont gérés automatiquement par Maven à partir du pom.xml. Ils sont téléchargés à partir d’entrepôt (par défaut maven central qui est public). Le cache local se trouve dans $HOME/.m2/repository.
Maven dispose de plugin pour gérer efficacement les versions des dependences et plugins: https://www.mojohaus.org/versions/versions-maven-plugin/index.html
Il est possible d’afficher les mises à jour disponibles des dépendances ou des propriétés (ici les transitives sont ignorées) voire de les mettres à jour:
%%shellcd /home/jovyan/work/src/github/ebpro/notebook-java-maven/MyAppHelloWorld# FIX : le chemin vers rules.xml dans le pom.xml est incorrectsed -i 's/<rulesUri>file:\/\/\/\/home\/runner\/_work\/maven-archetypes\/maven-archetypes\/maven-archetype-simple\/rules.xml<\/rulesUri>/<rulesUri>file:.\/rules.xml<\/rulesUri>/' pom.xml./mvnw --color always -ntp versions:display-dependency-updates \-D processDependencyManagementTransitive=false./mvnw --color always -ntp versions:display-property-updates \-D processDependencyManagementTransitive=false
[INFO] Scanning for projects...
[INFO]
[INFO] --------------< fr.univtln.bruno.samples:MyAppHelloWorld >--------------
[INFO] Building MyAppHelloWorld 0.1.0-SNAPSHOT
[INFO] from pom.xml
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- versions:2.17.1:display-dependency-updates (default-cli) @ MyAppHelloWorld ---
[INFO] The following dependencies in Dependency Management have newer versions:
[INFO] org.junit:junit-bom ................................. 5.11.0 -> 5.11.3
[INFO] org.testcontainers:testcontainers-bom ............... 1.20.1 -> 1.20.4
[INFO]
[INFO] The following dependencies in Dependencies have newer versions:
[INFO] ch.qos.logback:logback-classic ....................... 1.5.7 -> 1.5.12
[INFO] org.junit.jupiter:junit-jupiter ..................... 5.11.0 -> 5.11.3
[INFO] org.mockito:mockito-junit-jupiter ................... 5.12.0 -> 5.14.2
[INFO] org.testcontainers:junit-jupiter .................... 1.20.1 -> 1.20.4
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1.359 s
[INFO] Finished at: 2024-12-05T09:38:10Z
[INFO] ------------------------------------------------------------------------
[INFO] Scanning for projects...
[INFO]
[INFO] --------------< fr.univtln.bruno.samples:MyAppHelloWorld >--------------
[INFO] Building MyAppHelloWorld 0.1.0-SNAPSHOT
[INFO] from pom.xml
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- versions:2.17.1:display-property-updates (default-cli) @ MyAppHelloWorld ---
[INFO]
[INFO] The following version properties are referencing the newest available version:
[INFO] ${maven-clean-plugin.version} ................................. 3.4.0
[INFO] ${maven-compiler-plugin.version} ............................. 3.13.0
[INFO] ${maven-jar-plugin.version} ................................... 3.4.2
[INFO] ${maven-resources-plugin.version} ............................. 3.3.1
[INFO] The following version property updates are available:
[INFO] ${junit-jupiter.version} ........................... 5.11.0 -> 5.11.3
[INFO] ${logback-classic.version} .......................... 1.5.7 -> 1.5.12
[INFO] ${maven-deploy-plugin.version} ....................... 3.1.2 -> 3.1.3
[INFO] ${maven-failsafe-plugin.version} ..................... 3.3.1 -> 3.5.2
[INFO] ${maven-install-plugin.version} ...................... 3.1.2 -> 3.1.3
[INFO] ${maven-project-info-reports-plugin.version} ......... 3.6.2 -> 3.8.0
[INFO] ${maven-site-plugin.version} ....................... 3.12.1 -> 3.21.0
[INFO] ${maven-surefire-plugin.version} ..................... 3.3.1 -> 3.5.2
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 0.879 s
[INFO] Finished at: 2024-12-05T09:38:12Z
[INFO] ------------------------------------------------------------------------
POM Parent
Avec Maven, un fichier POM peut rapidement devenir volumineux. De plus, une base commune doit souvent être partagée entre plusieurs projets et/ou plusieurs membres d’une équipe. Comme il s’agit d’un modèle orienté objet, il est possible (et fortement conseillé) de factoriser les paramétrages communs dans un ou plusieurs POM parent. Par exemple, chaque POM d’un projet peut hériter de celui d’une équipe, qui hérite lui-même de celui de l’entreprise.
Pour créer un POM parent, il suffit de créer un projet contenant un fichier pom.xml dont le packaging est défini à pom, puis de le déposer dans un repository commun (par exemple, en utilisant mvn install sur chaque machine ou, de façon plus réaliste, en utilisant un entrepôt Maven).
<parent> <groupId>...</groupId> <artifactId>...</artifactId> <version>...</version></parent>La commande mvn help:effective-pom permet de visualiser le POM après intégration des ancêtres (dont celui par défaut).Un POM parent est proposé ici https://github.com/ebpro/maven-parentpom.Un archetype plus complet utilisant le pom parent précédent est proposé ici https://github.com/ebpro/maven-archetypes.::: {#cell-38 .cell tags='[]' vscode='{"languageId":"java"}' execution_count=16}``` {.java .cell-code}%%shellcd /home/jovyan/work/src/github/ebpro/notebook-java-maven/mvn --quiet --color always -U -ntp archetype:generate -B \ -DarchetypeGroupId=fr.ebruno.maven.archetypes \ -DarchetypeArtifactId=maven-archetype-withparent \ -DarchetypeVersion=0.1.9 \ -DgroupId=fr.univtln.bruno.samples \ -DartifactId=MyAppHelloWorldWithParent \ -Dversion=0.1.0-SNAPSHOT \ -DgithubAccount=ebpro
09:38:26.345 [main] INFO fr.univtln.bruno.samples.SampleTest -- Once before all tests.
09:38:26.349 [main] INFO fr.univtln.bruno.samples.SampleTest -- Before each test.
09:38:26.351 [main] INFO fr.univtln.bruno.samples.SampleTest -- After each test.
09:38:26.352 [main] INFO fr.univtln.bruno.samples.SampleTest -- Before each test.
09:38:26.354 [main] INFO fr.univtln.bruno.samples.SampleTest -- After each test.
09:38:26.356 [main] INFO fr.univtln.bruno.samples.SampleTest -- Once after all tests.
09:38:28.988 [fr.univtln.bruno.samples.App.main()] INFO fr.univtln.bruno.samples.App -- Hello world !
Il est possible d’afficher les mises à jour disponibles des plugins :
[INFO] Scanning for projects...
[INFO]
[INFO] ---------< fr.univtln.bruno.samples:MyAppHelloWorldWithParent >---------
[INFO] Building MyAppHelloWorldWithParent 0.1.0-SNAPSHOT
[INFO] from pom.xml
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- versions:2.17.1:display-plugin-updates (default-cli) @ MyAppHelloWorldWithParent ---
[INFO]
[INFO] All plugins with a version specified are using the latest versions.
[INFO]
[INFO] All plugins have a version specified.
[INFO]
[INFO] Project requires minimum Maven version for build of: 3.9.8
[INFO] Plugins require minimum Maven version of: null
[INFO]
[INFO] No plugins require a newer version of Maven than specified by the pom.
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 0.966 s
[INFO] Finished at: 2024-12-05T09:38:31Z
[INFO] ------------------------------------------------------------------------
Il est aussi possible de mettre à jour automatiquement :