Construction et gestion de
développement avec Maven 3.6
Bruno Mermet
octobre 2022
Maven : Kesako ?
●
Un outil de construction d'application
●
Génère une application « déployable » à partir d'un
code source
●
Compile
●
Exécute des tests
●
Un outil de gestion de développement
●
Gère aussi
– Documentation & Rapports
– Site web
– ...
Maven : choix sous-jacents
●
Privilégier la standardisation à la liberté (Convention over
Configuration)
●
Structure standard des répertoires d'une application
●
Cycle de développement standard d'une application
➔
Maven se débrouille souvent tout seul !
●
Factoriser les efforts
●
Un dépôt global regroupant les ressources/bibliothèques
communes
●
Des dépôts locaux
●
Un dépôt personnel (~/.m2)
●
Multiplier les possibilités
●
Une application légère
●
De nombreux plugins, chargés automatiquement au besoin
Maven : vocabulaire
●
Plugin
Extension de l'application de base, proposant un ensemble de buts
●
But (Goal)
Tâche proposée par un plugin permettant de lancer un certain
nombre d'action lorsqu'il est invoqué par mvn plugin:but.
Paramétré par -Dparam=valeur
●
Phase (Maven Lifecycle Phase)
Phase du cycle de développement d'un logiciel, généralement
associée à des buts et exécutée par mvn phase
●
Artefact (Artifact)
Application dont le développement est géré via Maven
●
POM (Project Object Model)
Fichier xml décrivant les spécificités du projets (par rapport à
[Link], décrit non pas tout, mais juste le « non standard »)
Plugins et buts
Exemples
●
Plugin archetype
●
Pour créer de nouveaux projets standards
●
Buts : generate, create
●
Plugin compiler
●
Pour la compilation de code java
●
But : compile, test-compile
●
Plugin surefire
●
Pour l'exécution des tests
●
But : test
Buts et phases
●
Exécution d'un but
●
Exécution du but seulement
●
Exécution d'une phase
●
Exécution de la phase précédente
●
Exécution des buts associés
Etapes du cycle de vie Maven par défaut
Déploiement Déploiement du code en local ou sur site distant
Tests d'intégration Préparation et exécution des tests d'intégration
Création du paquetage Génération du paquetage à déployer
Tests Préparation, compilation et exécution des tests
Compilation Compilation du code
Préparation des ressources
Préparation du code
Validation Vérification de la complétude du projet
Phases du cycle de vie Maven par défaut
1. De la Validation à la compilation
process-classes Post-traite les classes (optimisation du
byte-code par exemple)
Compilation
compile Compile (!) les sources
process-resources Copie et traite les ressources pour
Préparation inclusion dans le paquetage
des
ressources generate-resources Génère les ressources à inclure
dans le paquetage
process-sources Traite le code source, par exemple
pour filtrer certaines valeurs
Préparation
Du
code generate-sources Génère tout code source nécessaire
à la compilation
Vérifie que le projet est complet et que toutes
Validation validate
les informations requises sont disponibles
Phases du cycle de vie Maven par défaut
2. Tests
test Effectue les tests
test-compile Compile le code de test
process-test-resources Copie les ressources de tests dans le
répertoire de tests
Tests
generate-test-resources Crée les ressources nécessaires aux tests
process-test-sources Traite le code source des tests
generate-test-sources Génère le code source nécessaire aux tests
Phases du cycle de vie Maven par défaut
3. Du paquetage au déploiement
deploy Déploiement du paquetage sur un site distant
Pour utilisation/partage
Déploiement install Installation du paquetage dans le dépôt local
Vérification de la validité du paquetage
verify
Et de critères de qualités
Post-traitement suite aux tests d'intégration
post-integration-test (nettoyage par exemple)
Tests Déploie du paquetage sur un site dédié
D'Intégration integration-test Et effectue les tests d'intégration
pre-integration-test Configuration avant les tests d'intégration
Création package Création du paquetage
Du
Paquetage Effectue les opérations préalables à la
prepare-package
Création du paquetage
Cas particulier
Cycle de vie pour un fichier jar
Phase But associé
deploy deploy:deploy
install install:install
package jar:jar
test surefire:test
test-compile compiler:testCompile
process-test-resources resources:testResources
compile compiler:compile
process-resources resources:resources
Phases du cycle de vie Maven
pour le site
Phase But associé
site-deploy site:deploy
post-site
site site:site
pre-site
Phases du cycle de vie Maven
pour le nettoyage
Phase But associé
post-clean
clean clean:clean
pre-clean
pre-site
Project Object Model
Structure générale
Relations Paramètres pour la construction
Coordonnées Construction
groupId répertoires
artifactId extensions
version ressources
plugins
multi-modules
héritage Rapports
dépendances
Environnement de construction
Informations générales sur le projet
Informations sur l'environnement
Généralités
Environnement Maven
Participants
Profils
Licences
Project Object Model
Un premier exemple
<project <dependencies>
xmlns="[Link] <dependency>
xmlns:xsi="[Link] <groupId>junit</groupId>
ema-instance" <artifactId>junit</artifactId>
xsi:schemaLocation="[Link] <version>3.8.1</version>
g/POM/4.0.0 <scope>test</scope>
[Link] </dependency>
v4_0_0.xsd"> </dependencies>
<modelVersion>4.0.0</modelVersion> </project>
<groupId>[Link]</groupId>
<artifactId>EssaiProjetMaven</artifactId>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<name>EssaiProjetMaven</name>
<url>[Link]
Coordonnées maven
●
Identifiant
●
GroupId
– En général, le nom du domaine à l'envers
●
ArtifactId
– Ce que l'on veut
●
Version
– [Link]-qualifier
– Permet de spécifier une version minimale lors d'une
dépendance avec order <num,num,num,alpha>
●
Si contient SNAPSHOT, remplacé par dateHeureUTC lors de
la génération du package
●
Non importé par défaut
●
Packaging
●
Type de paquetage à produire (jar, war, ear, etc.)
Dépendances
●
Spécifiées par
●
Un identifiant (group/artifact/version)
●
Une portée (scope) : compile par défaut
●
Récupération du projet
●
Soit localement
●
Soit sur un dépôt distant
●
Version
●
3.8.1 : si possible 3.8.1
●
[3.8,3.9] : de 3.8 à 3.9 inclus
●
(3.8,4.0) : à partir de 3.8, mais avant 4.0
●
(,4.0) : antérieur à 4.0
●
[3.8,] : à partir de 3.8
●
[3.8.1] : 3.8.1 absolument
●
Portée
●
Compile : nécessaire à la compilation, et inclus dans le paquetage
●
Provided : nécessaire à la compilation, non packagé (ex : Servlets)
●
Runtime : nécessaire pour exécution et test, mais pas compilation (ex : driver jdbc)
●
Test : nécessaire uniquement pour les tests
●
System : comme provided + chemin à préciser, mais à éviter
Structure des répertoires
Répertoire Du Projet
●
[Link]
●
src
– main
●
java
●
resources
– test
●
java
●
resources
●
target
– classes
– test-classes
Installation de maven
Variables d'environnement à définir
●
M2_HOME
Doit contenir le répertoire d'installation de maven
●
PATH
Rajouter $M2_HOME/bin
●
JAVA_HOME
Doit contenir le répertoire d'installation de java
Création d'un projet Maven
Plugin archetype
●
Suggestion
●
mvn archetype:generate -DgroupId=monGroupe -
DartifactId=monAppli -Dversion=1.0-
SNASHPOT
●
Choisir le type de projet « maven-archetype-
quickstart » et sélectionnez la dernière version
●
Confirmer avec « Y »
●
Remarques
●
Les arguments non renseignés seront demandés à
l'exécution
Créer un projet Java depuis les
dernières versions
●
Maintenant, une version supérieure à java 1.5 est
recommandée. Plusieurs solutions :
– Rajouter les lignes suivantes dans le POM généré
avec l'archetype maven-archetype-quickstart :
<[Link]>1.8</[Link]>
<[Link]>1.8</[Link]>
– Utiliser un autre archetype comme :
[Link]:archetype-quickstart-jdk8
Structure d'un projet nouvellement créé
●
Commande
mvn archetype:generate -DgroupId=[Link] -
DartifactId=exemple -Dversion=1.0-SNAPSHOT
●
Structure
●
exemple
– [Link]
– src
●
main
– java
●
edu
●
mermet
●
[Link]
●
test
– java
●
edu
●
mermet
●
[Link]
Fichiers de base générés : [Link]
<?xml version="1.0" encoding="UTF-8"?> <plugin>
<artifactId>maven-resources-plugin</artifactId>
<project xmlns="[Link] <version>3.0.2</version>
xmlns:xsi="[Link] </plugin>
xsi:schemaLocation="[Link] <plugin>
[Link] <artifactId>maven-compiler-plugin</artifactId>
<modelVersion>4.0.0</modelVersion> <version>3.8.0</version>
<groupId>[Link]</groupId> </plugin>
<artifactId>exemple</artifactId> <plugin>
<version>1.0-SNAPSHOT</version> <artifactId>maven-surefire-plugin</artifactId>
<name>exemple</name> <version>2.22.1</version>
<!-- FIXME change it to the project's website --> </plugin>
<url>[Link] <plugin>
<artifactId>maven-jar-plugin</artifactId>
<properties> <version>3.0.2</version>
<[Link]>UTF-8</[Link]> </plugin>
<[Link]>1.7</[Link]> <plugin>
<[Link]>1.7</[Link]> <artifactId>maven-install-plugin</artifactId>
</properties> <version>2.5.2</version>
</plugin>
<dependencies> <plugin>
<dependency> <artifactId>maven-deploy-plugin</artifactId>
<groupId>junit</groupId> <version>2.8.2</version>
<artifactId>junit</artifactId> </plugin>
<version>4.11</version> <plugin>
<scope>test</scope> <artifactId>maven-site-plugin</artifactId>
</dependency> <version>3.7.1</version>
</dependencies> </plugin>
<plugin>
<build> <artifactId>maven-project-info-reports-plugin</artifactId>
<pluginManagement> <version>3.0.0</version>
<plugins> </plugin>
<plugin> </plugins>
<artifactId>maven-clean-plugin</artifactId> </pluginManagement>
<version>3.1.0</version> </build>
</plugin> </project>
Fichiers de base générés : [Link]
package [Link];
/**
* Hello world!
*
*/
public class App
{
public static void main( String[] args )
{
[Link]( "Hello World!" );
}
}
Fichiers de base générés : [Link]
package [Link];
import static [Link];
import [Link];
/**
* Unit test for simple App.
*/
public class AppTest
{
/**
* Rigorous Test :-)
*/
@Test
public void shouldAnswerWithTrue()
{
assertTrue( true );
}
}
Utilisation de base du projet
Compilation
●
Préambule
Exécuter toutes les commandes depuis le
répertoire contenant le fichier [Link]
●
Compilation
●
Commande
– mvn compile
●
Bilan
– exemple/target/classes/edu/mermet/[Link]
●
Exécution (à des fins de test)
mvn exec:java -[Link]=[Link]
Utilisation de base du projet
Packaging et Installation
●
Packaging
●
Commande
mvn package
●
Bilan
– Ne recompile pas le code, mais compile la classe de test
– Exécution avec succès du seul test unitaire
– Création de
●
exemple/target/test-classes
●
exemple/target/surefire-reports
●
exemple/target/[Link]
●
Installation
●
Commande
mvn install
●
Bilan
– Ré-exécution des tests*
– Création de $HOME/.m2/repository/edu/mermet/exemple/1.0-
SNAPSHOT/[Link], ...
*pour éviter cela, mvn install -[Link]=true
Utilisation de base du projet
Génération d'un site web
●
Commande
●
mvn site
●
Bilan
●
exemple/target/site
– css
●
[Link], [Link]
●
[Link], [Link]
– images
●
[Link], [Link]
●
[Link]
●
icon_error_sml.gif, icon_info_sml.gif
●
icon_success_sml.gif, icon_warning_sml.gif
●
logos
– [Link]
– [Link]
– [Link]
●
[Link]
Maven et les tests
● Exécution des tests à chaque invocation de la phase test
Évitement
– En ligne de commande : -[Link]=true
– Via le POM
<plugins><plugin>
<groupId>[Link]</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<skip>true</skip>
</configuration>
</plugin></plugins>
● Echec d'un test au moins => blocage de la phase package
Évitement
– En ligne de commande : -[Link]=true
– Via le POM
<plugins><plugin>
<groupId>[Link]</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<testFailureIgnore>true</testFailureIgnore>
</configuration>
</plugin></plugins>
Utilisation d'un jar externe
Exemple avec log4J
●
[Link] ●
[Link]
... package [Link];
<dependencies> import [Link];
<dependency> import [Link];
<groupId>log4j</groupId> import [Link];
<artifactId>log4j</artifactId>
<version>1.2.14</version> /**
</dependency> * Hello world!
<dependency> */
<groupId>junit</groupId> public class App
<artifactId>junit</artifactId> {
<version>4.11</version> private static Logger log = [Link]([Link]);
<scope>test</scope>
</dependency> public static void main( String[] args )
</dependencies> {
</project> ConsoleAppender ca = new ConsoleAppender(new
SimpleLayout());
[Link](ConsoleAppender.SYSTEM_ERR);
[Link](); [Link](ca);
[Link]("avant");
[Link]( "Hello World!" );
[Link]("Après");
}
}
●
Compilation/exécution
mvn compile
mvn exec:java -[Link]=[Link]
Utilisation de fichiers de ressources
●
exemple/src/main/resources/[Link]
coucou
●
[Link]
package [Link];
import [Link].log4j.*;
import [Link].*;
/**Hello world! */
public class App {
private static Logger log = [Link]([Link]);
public static void main( String[] args ) {
ConsoleAppender ca = new ConsoleAppender(new SimpleLayout());
[Link](ConsoleAppender.SYSTEM_ERR);
[Link]();
[Link](ca);
String message = "Hello world";
try {
InputStream is = [Link]().getResourceAsStream("[Link]");
BufferedReader br = new BufferedReader(new InputStreamReader(is));
message = [Link]();
[Link]();
} catch (IOException ioe) {}
[Link]("avant");
Compilation
[Link](message); mvn compile
[Link]("Après"); Conséquences
}
}
Création de exemples/target/classes/[Link]
Profils
●
Principe
Ensemble nommé de configurations dans le [Link]
●
Utilisation
●
Permettre de tester des configurations différentes (sur
sélection manuelle)
●
Permettre une configuration automatique selon la
plateforme d'exécution de Maven
Profil nommé avec sélection manuelle
<profiles>
<profile>
<id>production</id>
<build>
<plugins>
<plugin>
<groupId>[Link]</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<debug>false</debug>
<optimize>true</optimize>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
Profil activé automatiquement
<profiles>
<profile>
<id>dev</id>
<activation>
<jdk>1.5</jdk>
<os>
<name>Windows XP</name>
<family>Windows</family>
<arch>x86</arch>
<version>5.1.2600</version>
</os>
<property>
<name>customProperty</name>
<value>BLUE</value>
</property>
<file>
<exists>[Link]</exists>
<missing>[Link]</missing>
</file>
</activation>
...
</profile>
</profiles>
Profil activé par défaut
<profiles>
<profile>
<id>dev</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
...
</profile>
</profiles>
Héritage entre POMs
●
Principe
●
Tout « pom » hérite d'un autre
●
POM racine : « super-POM »
●
Définition d'un héritage
<parent>
<groupId>groupe</groupId>
<artifactId>projet</artifactId>
<version>version</version>
</parent>
●
Propriété
●
Transitivité
●
On hérite de toutes les propriétés du super-POM, mais
on peut les redéfinir
Maven et subversion
Plugin scm (Source Code Management)
●
Configuration dans le pom
<scm>
<connection>scm:svn:[Link]
_repo/trunk</connection>
<developerConnection>scm:svn:[Link]
[Link]/svn_repo/trunk</developerConnection>
<url>[Link]
</scm>
●
Utilisation Connection : pour la lecture seule
DeveloperConnection : pour l'écriture
● mvn scm:checkout
● mvn scm:update
● mvn scm:checkin
●
...
Projets multi-modules
●
Un répertoire parent avec un pom référençant les sous-
modules
<packaging>pom</packaging>
...
<modules>
<module>m1</module>
<module>m2</module>
</modules>
●
Un sous-répertoire par module, avec un pom par module
●
Utilisation
●
Depuis le répertoire parent
les commandes mvn s'appliquent à tous les modules, en
tenant compte des éventuelles dépendances
●
Depuis un sous-répertoire
les commandes ne s'appliquent qu'au sous-module courant
Quelques configurations pratiques
1. Junit 4 dernière version
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
Quelques configurations pratiques
1bis. Junit 5 dernière version
<dependency>
<groupId>[Link]<groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.9.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>[Link]</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.9.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>[Link]</groupId>
<artifactId>junit-jupiter-params</artifactId>
<version>5.9.1</version>
<scope>test</scope>
</dependency>
Quelques configurations pratiques
2. Java 8 (si pas défini dans les propriétés)
<build>
<plugins>
<plugin>
<groupId>[Link]</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.10.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
Quelques configurations pratiques
3. Jar exécutable
<build>
<plugins>
<plugin>
<groupId>[Link]</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.3.0</version>
<configuration>
<archive>
<manifest>
<mainClass>[Link]</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
</plugins>
</build>
Quelques configurations pratiques
4. OneJar (préférer Assembly)
<build>
<plugins>
<plugin>
<groupId>[Link]</groupId>
<artifactId>onejar-maven-plugin</artifactId>
<version>1.4.4</version>
<executions>
<execution>
<goals>
<goal>one-jar</goal>
</goals>
<configuration>
<mainClass>[Link]</mainClass>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
Quelques configurations pratiques
4bis. Assembly
<build>
<plugins>
<plugin>
<groupId>[Link]</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.4.2</version>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<archive>
<manifest>
<mainClass>[Link]</mainClass>
</manifest>
</archive>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
Quelques configurations pratiques
5. PostGres
<dependency>
<groupId>[Link]</groupId>
<artifactId>postgresql</artifactId>
<version>42.5.0</version
</dependency>
Tests unitaires et Tests d'intégration
●
Principe général
– Les tests unitaires sont lancés par surefire lors de la
phase « test »
– Les tests d'intégration sont lancés par failsafe lors de la
phase « integration-test », préalable à la phase
« verify »
Distinguer les tests d'intégration
●
De base
– Les tests unitaires sont dans des fichiers :
●
**/Test*.java
●
**/*[Link]
– les tests d'intégration sont dans des fichiers :
●
**/IT*.java
●
**/*[Link]
●
Sinon
– Configurable (voir doc.)
Configuration du plugin failsafe
<build>
<plugins>
<plugin>
<groupId>[Link]</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>3.0.0-M7</version>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
</execution>
</execution>
</plugin>
</plugin>
</build>
Intégration de rapports au site
Configuration générale
●
Dans la balise <build><plugins>...</plugins></build> :
<plugin>
<groupId>[Link]</groupId>
<artifactId>maven-project-info-reports-plugin</artifactId>
<version>3.4.1</version>
</plugin>
<plugin>
<groupId>[Link]</groupId>
<artifactId>maven-site-plugin</artifactId>
<version>4.0.0-M3</version>
<configuration>
<locales>en,fr</locales>
</configuration>
</plugin>
Code source navigable
●
Configuration
<reporting>
<plugins>
<plugin>
<groupId>[Link]</groupId>
<artifactId>maven-jxr-plugin</artifactId>
<version>3.3.0</version>
</plugin>
</plugins>
</reporting>
●
Exécution
mvn site
Rapport de test
●
Configuration
<reporting>
<plugins>
<plugin>
<groupId>[Link]</groupId>
<artifactId>maven-surefire-report-plugin</artifactId>
<version>3.0.0-M7</version>
</plugin>
</plugins>
</reporting>
●
Exécution
mvn site
Rapport Checkstyle (qualité de code)
●
Configuration
<reporting>
<plugins>
<plugin>
<groupId>[Link]</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
<version>3.2.0</version>
<configuration>
<configLocation>google_checks.xml</configLocation>
</configuration>
</plugin>
</plugins>
</reporting>
●
Exécution
mvn site
Javadoc
●
Configuration
<reporting>
<plugins>
<plugin>
<groupId>[Link]</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.4.1</version>
</plugin>
</plugins>
</reporting>
●
Exécution
mvn site