Débuter avec Maven

KX Messages postés 16733 Date d'inscription samedi 31 mai 2008 Statut Modérateur Dernière intervention 31 janvier 2024 - 14 mai 2022 à 16:04

Présentation de Maven

Maven est un outil de gestion de projets Java et Java EE, il permet notamment de :
  • créer une arborescence standard du code et de ses ressources
  • télécharger, mettre à jour et configurer les bibliothèques nécessaires au projet
  • compiler le projet, effectuer des tests unitaires sur le code et packager le résultat

Téléchargement et installation de Maven

Avertissement : L'utilisation de Maven requiert un accès internet ainsi que de l'espace disque pour conserver les fichiers téléchargés.

Le logiciel Maven est open source, il est disponible gratuitement sur le site officiel de la fondation Apache sous les noms "binary.zip" pour Windows et "binary.tar.gz" pour Unix.

Une fois téléchargée, décompressez le contenu de l'archive dans un répertoire dédié ("C:\Program Files\Apache" par exemple), vous devez ensuite configurer la variable d'environnement MAVEN_HOME correspondant à ce répertoire et ajouter le sous-répertoire \bin à la variable d'environnement PATH.

Si vous n'avez pas installé de JDK pour éditer du code Java, c'est le moment de le faire en vous rendant sur le site officiel. Sur le même principe vous devez également configurer la variable JAVA_HOME correspondant au répertoire d'installation de la JDK, ainsi qu'ajouter le répertoire \bin à la variable d'environnement PATH.

En résumé, vous devriez avoir trois variables d'environnement, avec ces valeurs par exemple :
JAVA_HOME   C:\Program Files\Java\jdk-17.0.3.1
MAVEN_HOME C:\Program Files\Apache\maven-3.8.5
PATH %JAVA_HOME%\bin;%MAVEN_HOME%\bin;%PATH%

Pour vérifier que tout est bien installé, vous pouvez ouvrir une invite de commande et taper ceci :
mvn --version

Cela générera normalement un affichage plus ou moins comme ceci, décrivant votre configuration :
Apache Maven 3.8.5 (3599d3414f046de2324203b78ddcf9b5e4388aa0)
Maven home: C:\Programs\Maven\apache-maven-3.8.5
Java version: 17.0.3.1, vendor: Oracle Corporation, runtime: C:\Program Files\Java\jdk-17.0.3.1
Default locale: fr_FR, platform encoding: Cp1252
OS name: "windows 11", version: "10.0", arch: "amd64", family: "windows"

Hello World avec Maven

Pour faire simple nous allons créer un projet "Hello World" avec Maven et décortiquer son fonctionnement. Créez pour cela un répertoire dédié (l'emplacement n'a aucune importance).

Ouvrez une invite de commandes et déplacer vous jusqu'au dossier que vous venez de créer, nous allons enfin entrer dans le vif du sujet !

Génération de l'archetype

Pour l'instant nous avons un dossier vide, nous allons demander à Maven de créer tout seul (ou presque) un projet de base en tapant la commande suivante :

mvn archetype:generate

Maven devrait alors se connecter au dépôt central https://search.maven.org/#browse, et commencer à télécharger un grand nombre de fichiers POM (Project Object Model) et JAR (Java ARchiver) qui lui sont utiles. Ceux-ci seront ensuite stockés par défaut dans votre dossier C:\Users\Name dans un répertoire nommé ".m2".
En stockant ces fichiers sur le disque, Maven n'aura alors plus besoin de les télécharger lors de la prochaine utilisation et ira directement les consulter dans le dépôt local.

Si vous travaillez au sein d'une entreprise (ou d'une université par exemple), celle-ci est peut-être équipée d'un dépôt d'entreprise qui stocke sur un serveur tous les fichiers téléchargés par Maven au sein du réseau et les redistribue aux utilisateurs qui en ont besoin en local sans avoir à repasser par le dépôt central (sauf lors d'une première demande) ce qui permet d'accélérer l'accès aux fichiers.

Ceci étant dit, vos téléchargements devraient maintenant être terminés et Maven a dû vous indiquer qu'il allait générer le projet en mode interactif.

C'est-à-dire qu'il va vous poser un certain nombre de questions auxquelles il va falloir répondre, le plus souvent parmi une liste de choix dont un par défaut.

Première question : choisir le type de projet. Ici Maven propose plusieurs centaines de types d'archetypes différents, voici un exemple d'affichage des dernières lignes que vous pourriez avoir :
3090: remote -> xyz.luan.generator:xyz-gae-generator (-)
3091: remote -> xyz.luan.generator:xyz-generator (-)
3092: remote -> za.co.absa.hyperdrive:component-archetype (-)
3093: remote -> za.co.absa.hyperdrive:component-archetype_2.11 (-)
3094: remote -> za.co.absa.hyperdrive:component-archetype_2.12 (-)
Choose a number or apply filter (format: [groupId:]artifactId, case sensitive contains): 1905:


Les lignes 1 à 3094 sont tous les choix possibles de projets. Remarque : la liste des projets peut varier au cours du temps alors vous n'en aurez peut-être pas 3094, mais ça n'a aucune importance. Ici nous allons uniquement nous intéresser au choix par défaut proposé (1905 dans l'exemple) dont voici la description :
1905: remote -> org.apache.maven.archetypes:maven-archetype-quickstart (An archetype which contains a sample Maven project.)


Entrons donc cette valeur par défaut afin de dire à Maven d'utiliser l'archetype "quickstart".

S'en suit une deuxième question concernant la version de l'archetype que nous voulons utiliser.
Choose org.apache.maven.archetypes:maven-archetype-quickstart version:
1: 1.0-alpha-1
2: 1.0-alpha-2
3: 1.0-alpha-3
4: 1.0-alpha-4
5: 1.0
6: 1.1
7: 1.3
8: 1.4
Choose a number: 8:

Là encore nous allons prendre la valeur par défaut (8 dans l'exemple), qui correspond en général à la dernière version stable. Maven peut alors télécharger le projet. Mais il faut le personnaliser.

La question suivante concerne le "groupId" il s'agit du nom de votre groupe, par exemple celui de Maven est "org.apache.maven", ici vous pouvez donc mettre ce que vous voulez à condition de respecter la syntaxe attendu, c'est-à-dire des lettres minuscules sans accent ni espace séparés par des points. Pour l'exemple je vais mettre "org.ccm.maven"

Vient ensuite l'"artifactId", il s'agit tout simplement du nom du projet, je mettrais ici "helloworld".

La question suivante concerne la version du projet. Maven utilise beaucoup les numéros de versions, il est donc important de comprendre qu'à chaque fois que vous générerez votre projet Maven, son numéro de version est susceptible d'être incrémenté. En précisant qu'il s'agit d'une version "snapshot" on s'assure que le projet sera bien considéré comme étant en cours de développement et donc que sa version ne sera pas incrémentée. Laissons alors cette valeur par défaut "1.0-SNAPSHOT".

Enfin une question concernant le package des sources du projet, par défaut Maven propose de mettre le même nom que pour le groupId : "org.ccm.maven"

Petit récapitulatif et demande de confirmation avec un "Y" et voilà notre premier projet Maven créé !

Remarque : il aurait été possible d'obtenir la même chose sans passer par le mode interactif, dans ce cas il faut préciser les différents paramètres obligatoires, Maven complétant les paramètres manquant avec les valeurs par défaut. Ce qui donne :
mvn archetype:generate -DarchetypeArtifactId=maven-archetype-quickstart -DarchetypeVersion=1.4 -DgroupId=org.ccm.maven -DartifactId=helloworld -DinteractiveMode=false

Arborescence du projet

Voici l'architecture du projet telle que générée avec maven-archetype-quickstart et les valeurs des paramètres passés en mode interactif plus haut :
helloworld
|- pom.xml
|- src
|- main
| |- java
| |- org
| |- ccm
| |- maven
| |- App.java
|- test
|- java
|- org
|- ccm
|- maven
|- AppTest.java

Nous avons donc 12 dossiers et 3 fichiers, dont voici le détail :

helloworld/src/main/java/org/ccm/maven/App.java :
package org.ccm.maven;

/**
 * Hello world!
 *
 */
public class App 
{
    public static void main( String[] args )
    {
        System.out.println( "Hello World!" );
    }
}

Rien de compliqué jusque là, Maven nous a simplement rempli le code d'un classique Hello World.

helloworld/src/main/java/org/ccm/maven/App.java :
package org.ccm.maven;

import static org.junit.Assert.assertTrue;

import org.junit.Test;

/**
 * Unit test for simple App.
 */
public class AppTest 
{
    /**
     * Rigorous Test :-)
     */
    @Test
    public void shouldAnswerWithTrue()
    {
        assertTrue( true );
    }
}

Ici c'est un petit peu plus compliqué si vous ne connaissez pas JUnit, il s'agit d'une classe de test unitaire, cela permet de faire automatiquement quelques vérifications après chaque compilation pour s'assurer que les modifications apportées au code ne perturbent pas ce qui fonctionnait déjà.

Remarque : ici le test est bidon, il vérifie simplement que true vaut true, ce qui est évidemment correct.

Enfin, voici le cœur de Maven, qui contient toute la configuration du projet :

helloworld/pom.xml
<?xml version="1.0" encoding="UTF-8"?>

<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>org.ccm.maven</groupId>
  <artifactId>helloworld</artifactId>
  <version>1.0-SNAPSHOT</version>

  <name>helloworld</name>
  <!-- FIXME change it to the project's website -->
  <url>http://www.example.com</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.7</maven.compiler.source>
    <maven.compiler.target>1.7</maven.compiler.target>
  </properties>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
  </dependencies>

  <build>
    <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
      <plugins>
        <!-- clean lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#clean_Lifecycle -->
        <plugin>
          <artifactId>maven-clean-plugin</artifactId>
          <version>3.1.0</version>
        </plugin>
        <!-- default lifecycle, jar packaging: see https://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_jar_packaging -->
        <plugin>
          <artifactId>maven-resources-plugin</artifactId>
          <version>3.0.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-compiler-plugin</artifactId>
          <version>3.8.0</version>
        </plugin>
        <plugin>
          <artifactId>maven-surefire-plugin</artifactId>
          <version>2.22.1</version>
        </plugin>
        <plugin>
          <artifactId>maven-jar-plugin</artifactId>
          <version>3.0.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-install-plugin</artifactId>
          <version>2.5.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-deploy-plugin</artifactId>
          <version>2.8.2</version>
        </plugin>
        <!-- site lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#site_Lifecycle -->
        <plugin>
          <artifactId>maven-site-plugin</artifactId>
          <version>3.7.1</version>
        </plugin>
        <plugin>
          <artifactId>maven-project-info-reports-plugin</artifactId>
          <version>3.0.0</version>
        </plugin>
      </plugins>
    </pluginManagement>
  </build>
</project>

Nous retrouvons notamment les différentes valeurs que nous avons paramétrées, ainsi que les dépendances à JUnit pour permettre de faire les tests. En configurant cette dépendance dans le pom, Maven sait qu'il devra aller télécharger la bibliothèque de JUnit et l'associer au projet afin que celui fonctionne. Vous n'avez donc pas à l'installer vous même !

Remarque : les différentes versions qui apparaissent dans la configuration du pom.xml étaient certainement les dernières au moment où l'archetype a été créé, mais depuis celles-ci ont évoluées et devraient être logiquement mises à jour dans le fichier pom.xml. Toutefois dans le cadre de cet article, nous pouvons nous contenter des valeurs par défaut.

Nous pouvons voir également la balise de packaging, qui est un jar. Cela signifie qu'après compilation le code sera archivé dans un fichier JAR.

Cependant il manque un petit quelque chose, en effet ce jar n'est pas exécutable ! Nous allons donc rajouter le point d'entrée en copiant ce bloc dans le pom.xml au niveau des lignes 51-54 :
        <plugin>
          <artifactId>maven-jar-plugin</artifactId>
          <version>3.0.2</version>
          <configuration>
            <archive>
              <manifest>
                <addClasspath>true</addClasspath>
                <mainClass>org.ccm.maven.App</mainClass>
              </manifest>
            </archive>
          </configuration>
        </plugin>

Compilation et exécution du programme

Maintenant que notre code source est complet et que la configuration du projet est terminée, nous allons pouvoir demander à Maven de construire le projet. Pour cela ouvrez une invite de commande dans le dossier "helloworld" et entrez cette commande :
mvn package

Cela va entraîner différentes actions, la validation du projet (qui va notamment aller télécharger tous les fichiers qui pourraient être manquants), la compilation du projet, l'exécution des tests unitaires et la création des archives jar. Notez que si l'une de ces étapes échoue, alors les suivantes ne seront pas exécutées.

Un nouveau dossier est apparu dans votre répertoire helloworld, il s'agit de "target", celui-ci contient les classes compilées (dans "classes" pour le programme et "test-classes" pour les tests unitaires), les rapports de tests ("surefire-reports"), ainsi que l'archive "helloworld-1.0-SNAPSHOT.jar" et quelques autres dossiers.

Vous pouvez donc maintenant lancer le programme avec la commande :
java -jar target/helloworld-1.0-SNAPSHOT.jar

Le résultat sera donc comme prévu : Hello World!

Pour aller plus loin

  • La description du projet via le fichier pom.xml permet notamment de s'affranchir de l'installation des dépendances. Si vous voulez basculer votre projet d'une machine à une autre, il n'y a qu'à copier les sources du projet. La régénération du projet se fera alors à l'identique sans problème de configuration.
  • Une fois la compilation et le packaging terminé, Maven peut déployer l'application directement sur le serveur et faire des tests d'intégrité afin de vérifier qu'il cohabite bien avec les autres applications de son environnement.
  • Maven est supporté par la plupart des éditeurs (IntelliJ, Eclipse...), vous pourrez donc à terme vous passer de l'invite de commandes et retrouver les fonctionnalités de Maven directement dans votre IDE préféré.
  • Gradle est un projet similaire à Maven, qui repose sur les même dépôts d'artifact.