Il ressemble à un engrenage bleu clair mais avec une tête de robot au milieu en blanc. Le robot a de gros yeux comme des contours de lunettes épaisses.
Icone Malt de Yann PicotIcone LinkedIn de Yann PicotIcone GitHub de Yann Picot
Personne travaillant sur des plans de conception. Photo prise par Pedro Miranda.

Documentations > Création de repository local avec Maven

Comment créer un repository local avec Maven ?

15/11/2024 - Auteur : Yann P

Paramétrage du projet

Je vais utiliser IntelliJ IDEA Community Edition. Mais si vous souhaitez créer votre projet Maven de toutes pièces, je vous invite à suivre le tutoriel officiel.

Créez votre projet et choisissez le bon JDK, celui qui fonctionnera avec vos librairies

Interface de création de projet sur IntelliJ IDEA.
Aperçu du fichier pom.xml montrant des détails comme le JDK et le nom du projet.

Installation d’une librairie (package) dans votre projet via le terminal

Téléchargez vos librairies. J’ai téléchargé deux librairies : android-junit-report-1.2.6 et javax.

1. Décompresser vos librairies

Instructions pour décompresser un fichier : étape 1, sélectionner les fichiers, clic droit, 'Décompresser tout'; étape 2, bouton 'Extraire'.
Fichiers .jar et leur contenu après décompression.
Icône 'i' entourée d'un cercle, indiquant un message important.La commande CMD fonctionne lorsqu’elle pointe directement sur le .jar de votre librairie. Pour plus de simplicité, mettez tous les fichiers .jar de vos librairies dans le même dossier vers lequel vous pointez pour l'installation.

2. S’assurer que la commande mvn est dans le path Windows

  • Ajoutez une nouvelle ligne dans la variable path de vos variables système en suivant les étapes. Ajoutez-y le chemin vers votre dossier bin de Maven /maven/lib/maven3/bin.
    Exemple :
  • Plaintext

    C:\cheminVerVotreInstallationIntteliJ\IntelliJ IDEA Community Edition 2024.3\plugins\maven\lib\maven3\bin
  • Suivez les étapes indiquées par les numéros sur les captures d'écran
  • Fenêtre de recherche Windows pour modifier les variables PATH.
    Fenêtre 'Propriétés système' de Windows montrant l'option 'Variables d'environnement'.
    Étapes pour ajouter un PATH dans le système Windows : 1. Double-cliquer sur 'Path' dans les variables système; 2. Cliquer sur 'Nouveau'; 3. Coller le chemin du dossier 'bin' de Maven; 4 et 5. Valider avec 'OK'.
  • Vérifiez que le lien avec Maven fonctionne dans un terminal sur votre IDE ou bien sur Windows (CMD) avec la commande mvn -v
  • Résultat attendu de la commande 'mvn -v' dans un terminal Windows.
Icône 'i' entourée d'un cercle, indiquant un message important.Redémarrez votre IDE si la commande ne fonctionne pas directement.

3. Installer la librairie

    bash

    mvn install:install-file
        -Dfile=<path-to-file>
        -DgroupId=<group-id>
        -DartifactId=<artifact-id>
        -Dversion=<version>
        -Dpackaging=<packaging>
        -DgeneratePom=true

    La commande à exécuter dans un terminal ressemble à ceci : La variable -Dfile pour le chemin jusqu’au fichier .jar. -DgroupId c’est l’identifiant unique de la librairie dans le projet. -DartifactId c'est le nom spécifique du projet ou module au sein du groupId. -Dversion c’est la version de la librairie, une suite de chiffres entrecoupée de points. S’il n’y en a pas, vous pouvez mettre '1.0' par exemple. -Dpackaging=jar c’est le format dans lequel est votre fichier à installer.


  • Modifier la commande avec votre déclaration de librairie, exemple :
  • bash

    mvn install:install-file -Dfile=C:\maven-libraries\android-junit-report-1.2.6.jar -DgroupId=com.android.tools -DartifactId=android-junit-report -Dversion=1.2.6 -Dpackaging=jar -DgeneratePom=true
    Icône 'i' entourée d'un cercle, indiquant un message important.Évitez tout passage à la ligne ou espace dans vos chemins, sinon cela ne fonctionnera pas.
  • Après avoir entré la commande, vous devriez avoir un log comme celui-ci si tout fonctionne correctement :
  • Plaintext

    [INFO] Scanning for projects...
    [INFO]
    [INFO] ------------------< org.apache.maven:standalone-pom >-------------------
    [INFO] Building Maven Stub Project (No POM) 1
    [INFO] --------------------------------[ pom ]---------------------------------
    [INFO]
    [INFO] --- install:3.1.2:install-file (default-cli) @ standalone-pom ---
    [INFO] pom.xml not found in android-junit-report-1.2.6.jar
    [INFO] Installing C:\cheminVersVotreFichierPointJar\documentation-local-repository\jars\android-junit-report-1.2.6.jar to C: \cheminVersVotreFichierPointJar\documentation-local-repository\create-a-local-repository\local-repository\android-junit-report\android-junit-report\1.2.6\android-junit-report-1.2.6.jar
    [INFO] Installing C:\Users\USERSI~1\AppData\Local\Temp\mvninstall5133595932557109365.pom to C:\cheminVersVotreFichierPointJar\documentation-local-repository\create-a-local-repository\local-repository\android-junit-report\android-junit-report\1.2.6\android-junit-report-1.2.6.pom
    [INFO] ------------------------------------------------------------------------
    [INFO] BUILD SUCCESS
    [INFO] ------------------------------------------------------------------------
    [INFO] Total time:  0.874 s
    [INFO] Finished at: 2024-11-15T16:39:21+01:00
    [INFO] ------------------------------------------------------------------------

Sinon, il faudra regarder erreur par erreur. Généralement, c’est le chemin qui ne correspond pas parfaitement. Ou la commande qui est mal formatée. On peut par exemple éviter les espaces dans les dossiers utilisés. Exemple de nom de dossier : Dossier projet, faire plutôt dossier-projet ou dossier_projet.

Comment lier le projet Java avec la librairie contenue dans le repository local ?

1. Déclaration du repository et celle du package

  • Déclarer le repository
  • xml

    <repositories>
        <repository>
            <id>local-repo</id>
            <url>file://${basedir}/local-repository/</url>
        </repository>
    </repositories>

    On déclare le repository dans le pom.xml à la racine du projet : file://${basedir}/ assurant la portabilité de la librairie. Les librairies sont dans le dossier /local-repository/ qui est à créer. C’est plus simple lorsque vous souhaitez transformer votre projet en FAT JAR.


  • Ajouter la définition du package précédemment installé
  • xml

    <dependencies>
        <dependency>
            <groupId>android.junit.report</groupId>
            <artifactId>junitreport</artifactId>
            <version>1.2.6</version>
            <scope>compile</scope>
        </dependency>
    </dependencies>

2. Synchroniser le projet Maven

Vous pouvez utiliser les outils d’IntelliJ ou votre IDE pour faire la synchronisation des librairies de votre projet.

Bouton de synchronisation Maven mis en évidence dans l'onglet IntelliJ IDEA.
Nouvelle bibliothèque récemment ajoutée visible dans les bibliothèques externes.

Ou vous pouvez faire un mvn clean install. La librairie devrait être visible dans vos dossiers de projets d’IntelliJ. Vous pouvez aussi essayer d’importer le fichier qu’il vous faut pour voir si le projet compile.

Pour aller plus loin, comment automatiser plusieurs installations de librairies dans un repository local ?

Le processus d’installation des librairies est très chronophage, c’est pourquoi je conseille un script. Via Python, nous pouvons parcourir le dossier rempli des librairies du projet à installer. Ensuite, une par une, via la commande CMD vue précédemment, nous les installons. Enfin, on crée une déclaration de la dépendance à copier-coller.


  • Positionner vos fichiers .jar au même endroit :
  • Un dossier sur windows nommé jars.

1. Exécuter des commandes CMD en Python

Python

import os

retour_commande = os.popen(r'mvn install:install-file -Dfile="<leCheminDuFichierJar>" -DgroupId="votreNomDeGroupeId" -DartifactId="votreArtifactId" -Dversion="laVersionDeLartifact" -Dpackaging=jar -DlocalRepositoryPath="cheminVersLeRepositoryFinal"')
print(retour_commande)

La commande est exécutée en CMD et vous récupérez le résultat de la commande via l'affichage en console du print(retour_commande).

2. Récupérer le nom des fichiers présents afin d'extraire un groupId et un artifactId.

Python

import os

for root, dirs, files in os.walk("leCheminDuDossierVersLesFichiersJar"):
    for file in files :
        artifactId= ".".join(file.split("-")[:-1])
        print(artifactId)
        version = ".".join((file.split("-")[-1]).split(".")[:-1])
        print(version)

Ce code très factorisé permet de récupérer l’artifactId et la version contenue dans le nom du fichier en deux lignes s'il est au bon format, exemple : "ma-librairie-2.3".

Python

import os

for root, dirs, files in os.walk("leCheminDuDossierVersLesFichiersJar"):
    for file in files :
        fichier = file.split("-")
        version = fichier[len(fichier)-1].split(".")
        artifactId = ""
        for i in range(0,len(fichier)-1) :
            if i == 0 :
                artifactId = fichier[i]
            else:
                artifactId = artifactId+"."+ fichier[i]
            version_full = ""
            for i in range(0,len(version)-1) :
                if i == 0 :
                    version_full = version[i]
                else:
                    version_full = version_full+"."+ version[i]
        print(artifactId)
        print(version_full)

Une version non factorisée de ce code mais avec des boules et des conditions.

3. Exemple de nommage de librairies

Python

import os

for root, dirs, files in os.walk("leCheminDuDossierVersLesFichiersJar"):
    for file in files :
        artifactId= ".".join(file.split("-")[:-1])
        print(artifactId)
        version = ".".join((file.split("-")[-1]).split(".")[:-1])
        print(version)
        retour_commande = os.popen(r'mvn install:install-file -Dfile="leCheminDuDossierVersLesFichiersJar" -DgroupId="'+artifactId+'" -DartifactId="'+artifactId+'" -Dversion="'+version+'" -Dpackaging=jar -DlocalRepositoryPath="cheminVersLeRepositoryFinal"')
        print(retour_commande)

Le résultat serait :

  • groupId = android.junit.report
  • artifactId = android.junit.report
  • version = 1.2.6


Ce n’est pas un nom standard, mais cela permet à Maven de récupérer le module et de le rendre accessible ensuite en utilisant la déclaration :

xml

<dependency>
    <groupId>android-junit-report</groupId>
    <artifactId>android-junit-report</artifactId>
    <version>1.2.6</version>
    <scope>compile</scope>
</dependency>

N’oubliez pas de faire une synchronisation comme pour Synchroniser le projet Maven. Deux manières de vérifier : soit en faisant un control-click sur le nom de votre artifactId dans votre pom.xml avec IDEA IntelliJ. Cela vous mène au fichier .pom de la librairie. Vous pouvez aussi mettre un import, pour mon exemple : import com.zutubi.android.junitreport.*; dans votre main.java et voir si cela compile.

4. Définir des conventions de nommage pour vos librairies

Vos librairies ont parfois une même racine, comme perf4j, org, be, etc. Vous pouvez mettre en place un filtre pour rendre plus cohérentes vos méthodes de déclaration.

Python

premier_mot = file.split("-")[0]
if (premier_mot == "perf4j") :
    retour_commande = os.popen(r'mvn install:install-file -Dfile='+DfileRacine + file+' -DgroupId="org.perf4j" -DartifactId="'+artifactId+'" -Dversion="'+version+'" -Dpackaging=jar '+DlocalRepositoryPath).read()
    print(retour_commande)
  • On y ajoute à la fin la possibilité de faire la saisie à la main pour les cas particuliers.
  • Python

    else :
        print(file)
        print("GroupId : ")
        saisieGid = input()
        print("ArtifactId : ")
        saisieAid = input()
        retour_commande = os.popen(r'mvn install:install-file -Dfile='+DfileRacine + file+' -DgroupId="'+saisieGid+'" -DartifactId="'+saisieAid+'" -Dversion="'+version+'" -Dpackaging=jar '+DlocalRepositoryPath).read()
        print(retour_commande)
  • Un exemple du code complet serait :
  • Python

    import os
    
    DfileRacine = r'C:/cheminVersFichiersJars/documentation-local-repository/jars/'
    DlocalRepositoryPath = r'-DlocalRepositoryPath=C:/cheminVersLeRepository/create-a-local-repository/local-repository/'
    
    liste_des_definition_pom_xml = []
    
    def pomXmlGenerationDef(groupId, artifactId, version) :
        liste_des_definition_pom_xml.append("<dependency>\n    <groupId>"+groupId+"</groupId>\n    <artifactId>"+artifactId+"</artifactId>\n    <version>"+version+"</version>\n    <scope>compile</scope>\n</dependency>")
    
    def affichageListeDesDefinitionPomXml() :
        for dependence in liste_des_definition_pom_xml :
            print(dependence)
    
    for root, dirs, files in os.walk(DfileRacine):
        for file in files :
            artifactId= ".".join(file.split("-")[:-1])
            print(artifactId)
            version = ".".join((file.split("-")[-1]).split(".")[:-1])
            print(version)
            premier_mot = file.split("-")[0]
            if (premier_mot == "perf4j") :
                retour_commande = os.popen(r'mvn install:install-file -Dfile='+DfileRacine + file+' -DgroupId="org.perf4j" -DartifactId="'+artifactId+'" -Dversion="'+version+'" -Dpackaging=jar '+DlocalRepositoryPath).read()
                print(retour_commande)
            elif (premier_mot == "opensaml") :
                print("opensaml")
                retour_commande = os.popen(r'mvn install:install-file -Dfile='+DfileRacine + file+' -DgroupId="org.opensaml" -DartifactId="'+artifactId+'" -Dversion="'+version+'" -Dpackaging=jar '+DlocalRepositoryPath).read()
                print(retour_commande)
                pomXmlGenerationDef("org.opensaml", artifactId, version)
            else :
                print(file)
                print("GroupId : ")
                saisieGid = input()
                print("ArtifactId : ")
                saisieAid = input()
                retour_commande = os.popen(r'mvn install:install-file -Dfile='+DfileRacine + file+' -DgroupId="'+saisieGid+'" -DartifactId="'+saisieAid+'" -Dversion="'+version+'" -Dpackaging=jar '+DlocalRepositoryPath).read()
                print(retour_commande)
    
    affichageListeDesDefinitionPomXml()
    
    print("Installation terminée ! Tous les fichiers JAR ont été lus.")

Cela rend les déclarations plus lisibles si vos filtres sont précis. Le code permet l'installation avec des nommages presque tous automatisés. Et l'affichage en console via affichageListeDesDefinitionPomXml() qui vous permet de copier-coller les déclarations dans le pom.xml. Faites une synchronisation après l'ajout des nouvelles déclarations (Synchroniser le projet Maven).

Vers une convention de nommage officielle ?

1. Utiliser le chemin de dossier le plus commun comme nom de groupId

Python

def extract_group_id_from_jar(jar_path):
    with zipfile.ZipFile(jar_path, 'r') as jar:
        # Récupérer les chemins des fichiers .class dans le JAR
        class_file_paths = [f for f in jar.namelist() if f.endswith(".class")]

        # Extraire les chemins des packages racines (éviter META-INF)
        valid_package_paths = [
            f.rsplit("/", 1)[0] for f in class_file_paths
            if "/" in f and not f.startswith("META-INF")
        ]

        # Si aucun package valide n'est trouvé, lever une exception
        if not valid_package_paths:
            raise ValueError("Aucun package valide trouvé dans les fichiers .class")

        # Identifier le package racine le plus fréquent
        most_common_package = Counter(valid_package_paths).most_common(1)[0][0]

        return most_common_package.replace("/", ".")

La librairie Counter nous permet ici d'identifier les chemins les plus fréquents. On peut, en récupérant tous les chemins menant à un .class émettre l'hypothèse que le chemin le plus peuplé de .class est le chemin le plus proche de la convention de nommage officielle des packages Maven. Dans mon exemple, la suite de dossiers la plus peuplée de .class est com.zutubi.android.junitreport pour android-junit-report-1.2.6 et javax.xml.bind pour javax.

2. Code complet de l'automatisation d'installation et de nommage

Pour mettre en marche le script, reprenez chaque étape :

  • Téléchargez vos librairies.
  • Mettez les .jar dans un seul dossier.
  • Créez un projet Maven.
  • Créez un dossier pour votre repository à la racine du projet.
  • Modifier la variable : DfileRacine par le chemin où se trouvent vos .jar. Mettez des / et non des \ pour votre chemin.
  • Modifier la variable : DlocalRepositoryPath par le chemin où se trouve votre repository local. Mettez des / et non des \ pour votre chemin.
  • Exécuter le code Python.
  • Copier-coller les dépendances affichées dans le terminal dans votre pom.xml à la racine.
  • Refaites une synchronisation du projet.
  • Importer et utiliser les librairies du repository local.

Python

import re, os, zipfile
from collections import Counter

# Fonction pour extraire le groupId à partir du fichier JAR
def extract_group_id_from_jar(jar_path):
    with zipfile.ZipFile(jar_path, 'r') as jar:
        # Récupérer les chemins des fichiers .class dans le JAR
        class_file_paths = [f for f in jar.namelist() if f.endswith(".class")]

        # Extraire les chemins des packages racines (éviter META-INF)
        valid_package_paths = [
            f.rsplit("/", 1)[0] for f in class_file_paths
            if "/" in f and not f.startswith("META-INF")
        ]

        # Si aucun package valide n'est trouvé, lever une exception
        if not valid_package_paths:
            raise ValueError("Aucun package valide trouvé dans les fichiers .class")

        # Identifier le package racine le plus fréquent
        most_common_package = Counter(valid_package_paths).most_common(1)[0][0]

        return most_common_package.replace("/", ".")

# Fonction pour extraire l'artifactId et la version à partir du nom du fichier JAR
def extract_artifact_id_and_version_from_filename(jar_path):
    # Extraire le nom du fichier JAR sans son chemin
    jar_filename = jar_path.rsplit("/", 1)[-1]
    # Retirer l'extension du fichier .jar
    base_filename = jar_filename.rsplit(".", 1)[0]

    # Séparer le nom du fichier sur le dernier tiret pour obtenir artifactId et version
    parts = base_filename.rsplit("-", 1)

    # Pattern vérifiant que c'est une suite de chiffre et de point à la fin du split du nom de fichier
    pattern = r"\b\d+(\.\d+)*\b"

    # Si le nom du fichier est en "unSeulMot" et non "unversion-1.0" ou ne possède pas de chiffre à la dernière position "un-mot" alors assigne la version à undifined.
    if len(parts) <= 2 or not re.search(pattern, parts[len(parts)-1]) :
        artifact_id = base_filename  # Tout le nom est l'artifactId
        version = "undefined"        # Pas de version détectée
    else :
        artifact_id, version = parts # On prends la artifact_id de la position 0 du tableau et version position 1.

    return [artifact_id, version]

# Fonction pour générer la dépendance Maven en XML à partir du JAR
def get_groupid_artifactid_version(jar_path):
    group_id, artifact_id, version = "", "", ""
    if os.path.exists(jar_path) :
        # Extraire l'artifactId, la version et le groupId à partir du JAR
        artifact_id, version = extract_artifact_id_and_version_from_filename(jar_path)
        group_id = extract_group_id_from_jar(jar_path)
    else :
        print(r'Le chemin : "'+ jar_path + r'" est inconnu du système.')

    return [group_id, artifact_id, version]

## Commande cmd de configuration des jar version Maven ##

DfileRacine = r'C:/cheminVersVosFichiesJars/jars/' # Position de vos jars dans votre système de fichiers
DlocalRepositoryPath = r'-DlocalRepositoryPath=C:/cheminVersVotreRepositoryLocal/local-repository/' # Position de votre repository local

# Liste d'affichage des déclarations à copier coller à la fin dans votre pom.xml
liste_des_definition_pom_xml = []

# Mise en forme d'une déclaration de dépendance
def pomXmlGenerationDef(groupId, artifactId, version) :
    liste_des_definition_pom_xml.append("<dependency>\n    <groupId>"+groupId+"</groupId>\n    <artifactId>"+artifactId+"</artifactId>\n    <version>"+version+"</version>\n    <scope>compile</scope>\n</dependency>")

# Affichage dans le termine des définitions de dépendance pour le copier coller
def affichageListeDesDefinitionPomXml() :
    for dependence in liste_des_definition_pom_xml :
        print(dependence)

# Parcourir les fichiers au chemin DfileRacine.
for file in os.listdir(DfileRacine):
    # N'exécuter les installations seulement sur les fichiers .jar
    if os.path.isfile(os.path.join(DfileRacine, file)) and file.endswith('.jar'):
        group_id, artifact_id, version = get_groupid_artifactid_version(DfileRacine + file)

        # Si les variables sont vides, c'est qu'il y a eu un problème avec le nom du fichier.
        if group_id != "" and artifact_id != "" and version != "" :
            retour_commande = os.popen(r'mvn install:install-file -Dfile='+DfileRacine + file+' -DgroupId="'+group_id+'" -DartifactId="'+artifact_id+'" -Dversion="'+version+'" -Dpackaging=jar '+DlocalRepositoryPath).read()
            print(retour_commande)
            pomXmlGenerationDef(group_id, artifact_id, version)
        else :
            print("Le fichier : "+file+ " n'a pas pu être traité ! Renommez-le au format 'nom-du-package' si pas de version ou 'nom-du-package-2.1.2'.' ")

affichageListeDesDefinitionPomXml()

print("Installation terminée ! Tous les fichiers JAR ont été lus.")
×