Blog technique
Quand (ne pas) utiliser mavenLocal() dans votre script de construction de Gradle
Gradle comme outil de construction
Si vous êtes comme moi et que vous travaillez dans une entreprise qui utilise Gradle comme outil de construction, vous vous êtes peut-être demandé, en écrivant les scripts de construction pour votre projet, ce qui devrait exactement aller dans ce bloc de référentiel. Et en particulier s’il faut inclure ou non mavenLocal(), et si oui où : comme premier élément ? Comme dernier ? La réponse brève est que vous ne voulez pas l’inclure.
Référentiels
Comme vous le savez très probablement si vous lisez ceci, Gradle peut exploiter le système Maven de composants (comme les bibliothèques Java) et de référentiel (comme le Nexus de Sonatype). Pour les utiliser, il vous suffit de déclarer une dépendance comme suit dans le script de construction de votre application Java :
dependencies {
implementation "com.fasterxml.jackson.core:jackson-core:2.9.9"
// ...
}
et Gradle se chargera de récupérer la version 2.9.9 de la bibliothèque centrale de Jackson fournie par FasterXML, et de l’inclure dans les chemins de classe appropriés lors de la compilation ou de l’exécution de votre application.
Ceci, à condition que Gradle sache où chercher cette bibliothèque. Et c’est précisément le but du bloc de référentiels, qui pourrait typiquement se lire comme suit :
repositories {
maven {
url "http://nexus.mycompany.loc/repository/internal"
mavenCentral()
}
}
Dans le bloc de référentiels ci-dessus, vous indiquez que lorsque vous recherchez une dépendance, Gradle doit d’abord interroger le référentiel Nexus interne de votre entreprise, puis le dépôt central Maven à l’adresse https://repo1.maven.org/maven2/ .
Le dépôt central est l’endroit où Gradle trouvera toutes les bibliothèques accessibles au public, comme celle de Jackson. Votre entreprise peut également utiliser un référentiel interne pour stocker les composants logiciels partagés entre les projets, ou entre les modules d’un projet.
Imaginez que votre application, en plus de Jackson, utilise pour votre projet du code provenant d’une bibliothèque partagée de DTO. Ses dépendances pourraient alors se lire :
dependencies {
implementation "com.mycompany.myproject:common-dtos:1.0.0-SNAPSHOT"
implementation "com.fasterxml.jackson.core:jackson-core:2.9.9"
// ...
}
Lorsqu’il compile le code de votre application, Gradle recherche les bibliothèques common-dtos et jackson-core, d’abord dans son cache de dépendances
dans le répertoire personnel, puis dans le répertoire interne de votre entreprise, puis dans le répertoire central de Maven.
Et maintenant, qu’en est-il de mavenLocal?
Jusqu’ici, tout fonctionne comme prévu. Pourtant, vous pourriez tomber sur certains scripts de construction Gradle avec un bloc des référentiels qui se lirait comme suit :
repositories {
maven {
mavenLocal()
url "http://nexus.mycompany.loc/repository/internal"
mavenCentral()
}
}
Au premier abord, cela semble raisonnable : n’interrogez pas le référentiel interne ou central si la dépendance est déjà présente dans le référentiel local. Quoique « le référentiel local » puisse signifier en réalité…
Il s’avère que le référentiel mavenLocal() n’est pas le cache de dépendance de Gradle. C’est un référentiel où vous pouvez déployer des composants avec ./gradlew publishToMavenLocal (si vous utilisez le plugin Gradle de maven-publish). Maintenant, pourquoi voudriez-vous déployer dans un référentiel local ? À mon avis, ce n’est pas le cas.
Le cas typique où j’envisagerais d’utiliser un référentiel local est de tester un changement dans une bibliothèque partagée sans le publier dans un référentiel visible par d’autres personnes que moi, afin d’être sûr de ce que je publie, quand je le publie. Toutefois, il existe de meilleurs moyens d’y parvenir.
Premier cas : la bibliothèque partagée que je veux tester est dans le même Gradle build que le code qui l’utilise. (Permettez-moi de rappeler que dans le langage Gradle, un « build » est la base de code qui est prise en compte lors de l’exécution d’une commande telle que ./gradlew build. C’est ce qu’Eclipse appelle un espace de travail, ou IntelliJ IDEA un projet). Dans ce cas, lorsque la bibliothèque commune des DTO est construite à partir, par exemple, d’un common-dtos sous-dossier de la racine du projet, précisant les dépendances de la demande en tant que dépendance d’un projet ) est suffisant :
dependencies {
implementation project(":common-dtos")
implementation "com.fasterxml.jackson.core:jackson-core:2.9.9"
// ...
}
Deuxième cas : la bibliothèque partagée se trouve dans une version différente de Gradle, son code source se trouve généralement dans un dépôt Git différent (nommons-le composants communs). Ensuite, j’utiliserai la fonction de composite build pour demander à Gradle d’utiliser la version des composants communs que j’ai clonée, plutôt que celle du référentiel, lors de la construction de mon application. Pour cela, en supposant que j’ai cloné les deux référentiels Git l’un à côté de l’autre sur mon disque (sinon, il s’agit juste de mettre en place le bon chemin relatif), il me suffit d’ajouter la ligne suivante dans le fichier settings.gradle à la racine de mon application :
includeBuild "../common-components"
Conclusion
Bien que vous puissiez rencontrer certains scripts de construction Gradle qui incluent mavenLocal() dans la liste des référentiels d’où il faut rechercher les dépendances, je ne vois pas de bonne raison de le faire. Il y a des cas d’utilisation où mavenLocal() pourrait ressembler à une solution, et c’était peut-être à une époque où les dépendances de projet et les composites build n’étaient pas disponibles dans Gradle. Mais maintenant, ils le sont. Pire encore : la documentation officielle de Gradle met en garde contre les différents problèmes qui pourraient survenir lors de l’utilisation de mavenLocal().
Restez informé grâce à notre blog Medium.
A propos de l’auteur
Bruno a rejoint DecisionBrain en 2016. Il a assuré la direction technique d’un des plus gros projets de DecisionBrain, puis a été l’architecte logiciel sénior de la plateforme technologique de l’entreprise. Il a plus de 20 ans d’expérience dans la conception et le développement de systèmes à base de connaissances, d’interfaces graphiques, de langages de programmation par règles métier et d’ingénierie logicielle. Bruno a obtenu un doctorat en informatique portant sur la preuve formelle de programmes à l’Université de Fribourg (Allemagne) en 2012.