> Note : Gradle permet de faire sensiblement la même chose. > Par faute de temps, nous nous concentrerons sur Maven. > Mais en bonus, par la suite, vous pouvez essayer de refaire le TP avec Gradle. ## Exo 1 : Créer un projet maven depuis zéro ### Installer maven Si vous utilisez SdkMan! ```shell sdk install maven ``` Si vous lancez un terminal depuis IntelliJ Idea, normalement une version de maven est chargée avec le terminal. Vérifiez que maven est bien installé ```shell mvn -version ``` Vous devriez obtenir une réponse similaire à ceci : ```text Apache Maven 3.9.11 (3e54c93a704957b63ee3494413a2b544fd3d825b) Maven home: /... Java version: 25.0.1, vendor: Eclipse Adoptium, runtime: /___/.sdkman/candidates/java/25.0.1-tem Default locale: fr_FR, platform encoding: UTF-8 OS name: "mac os x", version: "15.7.3", arch: "aarch64", family: "mac" ``` ### Pom minimaliste 1 - A la racine de ce dépôt, créer un fichier `pom.xml` Le `pom.xml` est le fichier qui décrit les dépendances d’un projet Maven. C’est un peu le même principe que `composer.json` en PHP et le `package.json` de javascript. Sauf que Maven est plus ancien, c’est en XML. ```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>tp06.maven</groupId> <artifactId>hello-maven</artifactId> <version>1.0-SNAPSHOT</version> <properties> <maven.compiler.source>25</maven.compiler.source> <maven.compiler.target>25</maven.compiler.target> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> </project> ``` Vérifier que le fichier est valide à l’aide de la commande `mvn install`. ```shell mvn compile ``` Le résultat devrait être en succès. ```text ... [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 0.653 s [INFO] Finished at: 2026-01-19T22:10:53+01:00 [INFO] ------------------------------------------------------------------------ ``` Un dossier `target` est créé. Il ne contient rien d'intéressant pour le moment. > 🚨 Il est important d'exclure le dossier `target` de git car on ne veut versionner que les sources `.gitignore` ```.gitignore target ``` ### Intégration avec IntelliJ Idea Clic droit sur `pom.xml` > `Add as maven project` Une fois le Projet maven associé au projet Idea, on dispose d'intégrations intéressantes. Menu latéral Maven dans IntelliJ Idea ![](idea_maven_01.png) Pour en savoir plus rendez vous sur [la documentation des outils maven](https://www.jetbrains.com/help/idea/2025.3/maven-projects-tool-window.html?reference.toolWindows.mavenProjects&utm_source=product&utm_medium=link&utm_campaign=IU&utm_content=2025.3) dans IntelliJ. Parmi les fonctionnalités les plus utiles: Télécharger les sources et la documentation. ![img.png](idea_maven_download_sources_docs.png) Executer des commandes maven : "Execute maven goals". ![img.png](idea_execute_maven_goals.png) > 🚨 Quand vous modifiez le fichier pom.xml il faut penser à synchroniser les changements. Sinon ils ne seront pas pris en compte dans IntelliJ. ![idea-maven-sync-changes.png](idea-maven-sync-changes.png) ### Compilons du code ! Créer une classe `Main` a l'emplacement suivant. `src/main/java/tp06/maven/Main.java` ```java package tp06.maven; public class Main { static void main(String[] args) { String target = "Maven"; if (args.length > 0) { target = args[0]; } System.out.println("Hello " + target + " !"); } } ``` > 💡 Il est important de respecter la hiérarchie de dossier car maven s'appuie sur une convention par défaut pour les arborescences de fichiers. > ```text > ├── pom.xml > └── src > ├── main > │ ├── java > │ │ └── tp06 > │ │ └── maven > │ │ └── Main.java > │ └── resources > └── test > ├── java > └── resources > ``` Lancez la commande de compilation. ```shell mvn compile ``` Retournons dans le dossier `target`. On y trouve désormais les classes compilées. ```text target ├── classes │   └── tp06 │   └── maven │   └── Main.class └── ... ``` ### Exécuter le code compilé Pour ajouter des fonctionnalités à notre "build maven", on peut ajouter des plugins dans le POM. Il en existe une multitude. - Les plugins officiels peuvent se trouver à https://maven.apache.org/plugins/ ```xml <project> <!-- ... --> <build> <plugins> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>exec-maven-plugin</artifactId> <version>3.6.2</version> <configuration> <mainClass>tp06.maven.Main</mainClass> </configuration> </plugin> </plugins> </build> <!-- ... --> </project> ``` Grâce à ce nouveau plugin, je peux indiquer à maven de lancer mon programme ```shell mvn exec:java ``` ### Plugins Un certain nombre de plugins sont disponibles par défaut et sont préconfigurés avec des valeurs par défaut. C'est le cas du plugin de compilation qu'on a utilisé précédemment. > 💡 Quelques plugins courants > - `clean` : supprime le code dans `target` > - `compiler` : compilation du code et/ou des tests > - `surefire` : execution de tests automatisés et de rapports > - `exec` : exécution de code (ex. un programme Main) > - `jar` : construit une archive jar pour le projet courant > - `resources` : copie les ressources (fichiers additionnels externes au code mais inclus dans le classpath) dans le dossier de sortie > - `site` : génère un site web avec des informations sur le projet > - `install` : copie les artefacts du projet dans le dépôt local de l'utilisateur (en général dans `$HOME/.m2`) > - `deploy` : déploiement d'un artefact sur un dépôt distant Les plugins ont également des goals internes qu'on peut déclencher explicitement. ```shell # Ex. lancer le goal help du plugin compiler mvn compiler:help ``` Si on devait l'ajouter au POM, voici ce qu'on ajouterait. ```xml <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> </plugin> ``` Par défaut, pour les plugins officiels, la version est implicite. On voit d'ailleurs la version du plugin dans le résultat console de l'exécution. ```shell mvn compile ``` Par défaut dans mon cas, la version du plugin compiler est 3.13.0. ```text 👇 👇 [INFO] --- compiler:3.13.0:compile (default-compile) @ hello-maven --- [INFO] Nothing to compile - all classes are up to date. [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 0.234 s [INFO] Finished at: 2026-01-19T22:32:18+01:00 [INFO] ------------------------------------------------------------------------ ``` Si je veux utiliser une version précise (une version plus récente par exemple), je peux spécifier la version. ```xml <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.14.1</version> </plugin> ``` ```shell mvn compile ``` > 💡 Il est parfois nécessaire d'utiliser une version récente du plugin compiler quand de nouvelles versions de Java sortent. ### Cycles de vie https://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html ### Profiles Les profiles permettent de paramétrer différemment le projet. Très pratique quand on veut lancer ou construire un projet pour un environnement différent. ```xml <project> <!-- ... --> <profiles> <profile> <id>World</id> <build> <plugins> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>exec-maven-plugin</artifactId> <configuration> <mainClass>tp06.maven.Main</mainClass> <arguments>World</arguments> </configuration> </plugin> </plugins> </build> </profile> </profiles> </project> ``` Pour activer un profil en ligne de commande ajouter `-P` suivi de l'id du profile. ```shell mvn -P World exec:java ``` ```text Hello World ! [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 0.178 s [INFO] Finished at: 2026-01-19T22:45:17+01:00 [INFO] ------------------------------------------------------------------------ ``` ## Exercice 2 : dépendances Une fois qu'on a un Projet maven, on peut facilement ajouter des dépendances dans le pom.xml pour inclure du code extérieur dans notre projet. - Directes : déclarées dans `<dependency>` - Transitives : requises par les dépendances directes, elles sont également tirées Pour afficher l'arbre des dépendances. ```shell mvn dependency:tree ``` Exemple de rapport d'arbre de dépendances ```text [INFO] [INFO] ---------------< school.coda.template:template-java-mvn >--------------- [INFO] Building template-java-mvn 1.0-SNAPSHOT [INFO] from pom.xml [INFO] --------------------------------[ jar ]--------------------------------- [INFO] [INFO] --- dependency:3.7.0:tree (default-cli) @ template-java-mvn --- [INFO] school.coda.template:template-java-mvn:jar:1.0-SNAPSHOT [INFO] +- org.xerial:sqlite-jdbc:jar:3.51.0.0:compile [INFO] +- org.junit.jupiter:junit-jupiter:jar:5.11.4:test [INFO] | +- org.junit.jupiter:junit-jupiter-api:jar:5.11.4:test [INFO] | | +- org.opentest4j:opentest4j:jar:1.3.0:test [INFO] | | +- org.junit.platform:junit-platform-commons:jar:1.11.4:test [INFO] | | \- org.apiguardian:apiguardian-api:jar:1.1.2:test [INFO] | +- org.junit.jupiter:junit-jupiter-params:jar:5.11.4:test [INFO] | \- org.junit.jupiter:junit-jupiter-engine:jar:5.11.4:test [INFO] | \- org.junit.platform:junit-platform-engine:jar:1.11.4:test [INFO] +- org.assertj:assertj-core:jar:3.26.3:compile [INFO] | \- net.bytebuddy:byte-buddy:jar:1.14.18:compile [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 0.397 s [INFO] Finished at: 2026-01-19T23:39:11+01:00 [INFO] ------------------------------------------------------------------------ ``` `school.coda:projet-a` ```xml <project> <groupId>school.coda</groupId> <artifactId>projet-a</artifactId> <version>1.0.9</version> <dependencies> <dependency> <dependency> <groupId>school.coda</groupId> <artifactId>sqlite-helpers</artifactId> <version>2.5</version> </dependency> </dependency> </dependencies> </project> ``` `school.coda:sqlite-helpers` ```xml <project> <groupId>school.coda</groupId> <artifactId>sqlite-helpers</artifactId> <version>2.5</version> <dependencies> <dependency> <groupId>org.xerial</groupId> <artifactId>sqlite-jdbc</artifactId> <version>3.51.0.0</version> </dependency> </dependencies> </project> ``` Dans cet exemple, `school.coda:projet-a` dépend de `school.coda:sqlite-helpers` qui lui-même dépend de `org.xerial:sqlite-jdbc`. `school.coda:projet-a` dépend transitivement (indirectement) de `org.xerial:sqlite-jdbc`. ### Dépendances de production Ces dépendances seront utilisées dans le projet compilé livré. **Exemples** Driver JDBC pour la base de données SQLite ```xml <dependency> <groupId>org.xerial</groupId> <artifactId>sqlite-jdbc</artifactId> <version>3.51.0.0</version> </dependency> ``` > 💡 S'il n'est pas explicité : `<scope>compile</scope>` Il existe différents scopes - `compile` (défaut) : dépendance directe. transitive. - `provided` : indique que les dépendances nécessaires doivent être fournies par le JDK ou un conteneur. Ces dépendances **ne sont pas** transitives. ### Dépendances de test Ces dépendances sont inclues pour l'exécution des tests automatisés mais ne seront pas inclues dans l'archive de production. ```xml <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter</artifactId> <version>5.11.4</version> <scope>test</scope> </dependency> ``` > 💡 utiliser le `<scope>test</scope>` pour indiquer qu'une dépendance ne doit être utilisée que dans les tests. ### Maintenance des dépendances Il est important de mettre à jour ses dépendances. En particulier quand elles sont sujettes à des failles de sécurité. ```shell mvn io.github.mfoo:libyear-maven-plugin:analyze ``` ## Exercice 3 : packaging et livrables ## Exercice 4 : install pour déployer localement Créer un nouveau projet dans un dossier ailleurs que dans le projet courant. `pom.xml` minimaliste ```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>local.sample</groupId> <artifactId>lib1</artifactId> <version>1.0-SNAPSHOT</version> <properties> <maven.compiler.source>25</maven.compiler.source> <maven.compiler.target>25</maven.compiler.target> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> </project> ``` `src/main/java/local/sample/Lib1.java` ```java package local.sample.lib1; public class Lib1 { public String hello() { return "Hello Lib1"; } } ``` Depuis ce dossier lancer la commande install. ```shell mvn install ``` Cette commande copie les artefacts compilés dans le dépôt local. --- Retournez dans votre projet initial `pom.xml` ```xml <dependency> <groupId>local.sample</groupId> <artifactId>lib1</artifactId> <version>1.0-SNAPSHOT</version> </dependency> ``` Lancez la compilation (ou rafraichissez maven dans IntelliJ) ```shell mvn compile ``` Vous pouvez désormais importer le code du projet lib1 dans votre projet. ```java package tp06.maven; import local.sample.lib1.Lib1; public class Main { static void main(String[] args) { System.out.println(new Lib1().hello()); } } ``` > 💡 Bien entendu, cela ne fonctionne que dans votre dépôt local. > Si vous voulez partager votre code au dela de votre machine, vous devrez le déployer d'un un dépôt maven distant. ## Exercice 5 : pom parent pour mettre en commun des configurations ## Exercice 6 : projets multi-modules ## Exercice 7 : faire un site ```xml <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-site-plugin</artifactId> <version>3.21.0</version> </plugin> ``` ```shell mvn site:run ``` ## Exercice 8 : déployer sur un nexus <!-- TODO: Dans cette étape le prof va lancer un serveur nexus pour expérimenter --> Ajouter l'adresse du nexus dans le pom.xml ou le pom parent. ```xml <distributionManagement> <repository> <id>coda_lab</id> <url>https://nexus.baldir.fr/repository/coda_lab/</url> <name>coda_lab</name> </repository> </distributionManagement> <repositories> <repository> <id>coda_lab</id> <url>https://nexus.baldir.fr/repository/coda_lab/</url> <name>coda_lab</name> </repository> </repositories> ``` Ajouter l'id du serveur dans un fichier `~/.m2/settings.xml`. ```xml <!-- Maven settings.xml template for publishing to Custom repository --> <!-- Copy this file to ~/.m2/settings.xml and fill in your credentials --> <settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"> <servers> <server> <id>coda_lab</id> <username>coda_deploy</username> <password>deploy</password> </server> </servers> </settings> ```