Maven Polyglot

Maven Polyglot

1. Vue d'ensemble

Maven Polyglot est un ensemble d'extensions principales de Maven qui permet d'écrire le modèle POM dans n'importe quel langage. Cela inclut de nombreux scripts et langages de balisage autres que XML.

Le principal objectif de Maven polyglot est d’échapper à XML, car ce n’est plus le langage de prédilection de nos jours.

Dans ce didacticiel, nous commencerons par comprendre le concept d'extension de base Maven et le projet Maven Polyglot.

Ensuite, nous montrerons comment écrire une extension de noyau Maven qui permet de construire le modèle POM à partir d'un fichier JSON plutôt que des fameuxpom.xml.

2. Mécanisme de chargement d'extension de noyau Maven

The Maven core extensions are plugins loaded at Maven initialization et avant le début de la construction du projet Maven. Ces plugins permettent de changer le comportement de Maven sans changer le noyau.

Par exemple, un plugin chargé au démarrage peut remplacer le comportement par défaut de Maven et peut lire le modèle POM à partir d'un autre fichier que lespom.xml.

Techniquement,a Maven core extension is a Maven artifact declared in an extensions.xml file:

${projectDirectory}/.mvn/extensions.xml

Voici un exemple d’extension:



    
        com.example.maven.polyglot
        maven-polyglot-json-extension
        1.0-SNAPSHOT
    

Enfin, nous devons noter quethis mechanism requires Maven 3.3.1 or higher.

3. Maven Polyglot

Maven Polyglot is a collection of core extensions. Chacun de ces éléments est responsable de la lecture du modèle POM à partir d'un script ou d'un langage de balisage.

Maven Polyglot fournit des extensions pour les langues suivantes:

+-----------+-------------------+--------------------------------------+
| Language  | Artifact Id       | Accepted POM files                   |
+-----------+-------------------+--------------------------------------+
| Atom      | polyglot-atom     | pom.atom                             |
| Clojure   | polyglot-clojure  | pom.clj                              |
| Groovy    | polyglot-groovy   | pom.groovy, pom.gy                   |
| Java      | polyglot-java     | pom.java                             |
| Kotlin    | polyglot-kotlin   | pom.kts                              |
| Ruby      | polyglot-ruby     | pom.rb, Mavenfile, Jarfile, Gemfile  |
| Scala     | polyglot-scala    | pom.scala                            |
| XML       | polyglot-xml      | pom.xml                            |
| YAML      | polyglot-yaml     | pom.yaml, pom.yml                    |
+-----------+-------------------+--------------------------------------+

Dans les sections suivantes, nous allons d'abord examiner la création d'un projet Maven dans l'une des langues prises en charge ci-dessus.

Ensuite, nous allons écrire notre extension pour prendre en charge un POM basé sur JSON.

4. Utilisation d'une extension Maven Polyglot

Une option pour construire un projet Maven basé sur un langage différent de XML consiste à utiliser l'un des artefacts fournis par le projet Polyglot.

Dans notre exemple,we’ll create a Maven project with a pom.yaml configuration file.

La première étape consiste à créer le fichier d’extension de base Maven:

${projectDirectory}/.mvn/extensions.xml

Ensuite, nous ajouterons le contenu suivant:



    
        io.takari.polyglot
        polyglot-yaml
        0.3.1
    

N'hésitez pas à ajuster lesartifactId à la langue choisie en fonction des langues ci-dessus et à vérifier si desnew version sont disponibles.

La dernière étape consiste à fournir les métadonnées du projet dans le fichierYAML:

modelVersion: 4.0.0
groupId: com.example.maven.polyglot
artifactId: maven-polyglot-yml-app
version: 1.0-SNAPSHOT
name: 'YAML Demo'

properties: {maven.compiler.source: 1.8, maven.compiler.target: 1.8}

Nous pouvons maintenant exécuter notre construction comme nous le faisons habituellement. Par exemple, nous pouvons appeler la commande:

mvn clean install

5. Utilisation du plugin Polyglot Translate

Une autre option pour obtenir un projet basé sur l'une des langues prises en charge consiste à utiliser lespolyglot-translate-plugin.

Cela signifie que nous pouvons partir d'un projet Maven existant avec unpom.xml. traditionnel

Ensuite,we can convert the existing pom.xml project to the desired polyglot by using the translate plugin:

mvn io.takari.polyglot:polyglot-translate-plugin:translate -Dinput=pom.xml -Doutput=pom.yml

6. Ecrire une extension personnalisée

Comme JSON ne fait pas partie des langages fournis par le projet Maven Polyglot,we’ll implement a simple extension that allows reading project metadata from a JSON file.

Notre extension fournira une implémentation personnalisée de l'API MavenModelProcessor qui remplacera l'implémentation par défaut de Maven.

Pour ce faire, nous allons modifier le comportement de la façon de localiser le fichier POM et de lire et transformer les métadonnées en API MavenModel.

6.1. Dépendances Maven

Nous allons commencer par créer un projet Maven avec les dépendances suivantes:


    org.apache.maven
    maven-core
    3.5.4
    provided


    com.fasterxml.jackson.core
    jackson-databind
    2.9.6

Iciwe use the maven-core dependency as we’ll implement a core extension. La dépendanceJackson est utilisée pour désérialiser le fichier JSON.

Et comme Maven utilise le conteneur d'injection de dépendance Plexus,we need our implementation to be a Plexus component. Nous avons donc besoin de ce plugin pour générer les métadonnées Plexus:


    org.codehaus.plexus
    plexus-component-metadata
    1.7.1
    
        
            
                generate-metadata
            
        
    

6.2. L'implémentation personnalisée deModelProcessor

Maven construit le modèle POM en invoquant la méthodeModelBuilder.build() qui à son tour délègue à la méthodeModelProcessor.read().

Maven fournit une implémentation deDefaultModelProcessor qui par défaut lit le modèle POM à partir d'un fichierpom.xml situé dans le répertoire racine ou spécifié comme commande de paramètre.

En conséquence, nous fournirons une implémentation personnalisée deModelProcessor qui remplacera le comportement par défaut. C'est l'emplacement de l'emplacement du fichier de modèle POM et comment le lire.

Commençons donc par créer une implémentationCustomModelProcessor et marquez-la comme composant Plexus:

@Component(role = ModelProcessor.class)
public class CustomModelProcessor implements ModelProcessor {

    @Override
    public File locatePom(File projectDirectory) {
        return null;
    }

    @Override
    public Model read(
      InputStream input,
      Map options) throws IOException, ModelParseException {
        return null;
    }
    //...
}

The @Component annotation will make the implementation available for injection by the DI container (Plexus). Ainsi, lorsque Maven a besoin d'une injection deModelProcessor dans lesModelBuilder,, le conteneur Plexus fournira cette implémentation et non lesDefaultModelProcessor.

Ensuite,we’ll provide the implementation for the locatePom() method. Cette méthode renvoie le fichier dans lequel Maven lira les métadonnées du projet.

Nous retournerons donc un fichierpom.json s'il existe, sinon, lespom.xml comme nous le faisons habituellement:

@Override
public File locatePom(File projectDirectory) {
    File pomFile = new File(projectDirectory, "pom.json");
    if (!pomFile.exists()) {
        pomFile = new File(projectDirectory, "pom.xml");
    }
    return pomFile;
}

L'étape suivante consiste à lire ce fichier et à le transformer en modèle Maven. Ceci est réalisé par la méthode read ():

@Requirement
private ModelReader modelReader;

@Override
public Model read(InputStream input, Map options)
  throws IOException, ModelParseException {

    FileModelSource source = getFileFromOptions(options);
    try (InputStream is = input) {
        //JSON FILE ==> Jackson
        if (isJsonFile(source)) {
            ObjectMapper objectMapper = new ObjectMapper();
            return objectMapper.readValue(input, Model.class);
        } else {
            // XML FILE ==> DefaultModelReader
            return modelReader.read(input, options);
        }
    }
    return model;
}

Dans cet exemple, nous vérifions si le fichier est un fichier JSON et nous utilisons le Jackson pour le désérialiser en MavenModel. Sinon, c'est un fichier XML normal, et il sera lu par les MavenDefaultModelReader.

Nous devons construire l'extension, qui sera prête à être utilisée:

mvn clean install

6.3. Utiliser l'extension

Pour démontrer l'utilisation de l'extension, nous utiliserons un projet Web Spring Boot.

Tout d'abord, nous allons créer un projet Maven et supprimer lespom.xml.

Ensuite,we’ll add the extension that we have implemented above, in ${projectDirectory}/.mvn/extensions.xml:



    
        com.example.maven.polyglot
        maven-polyglot-json-extension
        1.0-SNAPSHOT
    

Et enfin, nous créons lespom.json avec le contenu suivant:

{
  "modelVersion": "4.0.0",
  "groupId": "com.example.maven.polyglot",
  "artifactId": "maven-polyglot-json-app",
  "version": "1.0.1",
  "name": "Json Maven Polyglot",
  "parent": {
    "groupId": "org.springframework.boot",
    "artifactId": "spring-boot-starter-parent",
    "version": "2.0.5.RELEASE",
    "relativePath": null
  },
  "properties": {
    "project.build.sourceEncoding": "UTF-8",
    "project.reporting.outputEncoding": "UTF-8",
    "maven.compiler.source": "1.8",
    "maven.compiler.target": "1.8",
    "java.version": "1.8"
  },
  "dependencies": [
    {
      "groupId": "org.springframework.boot",
      "artifactId": "spring-boot-starter-web"
    }
  ],
  "build": {
    "plugins": [
      {
        "groupId": "org.springframework.boot",
        "artifactId": "spring-boot-maven-plugin"
      }
    ]
  }
}

Nous pouvons maintenant exécuter le projet avec la commande:

mvn spring-boot:run

7. Conclusion

Dans cet article, nous avons montré comment modifier le comportement par défaut de Maven via le projet Maven Polyglot. Pour atteindre cet objectif, nous avons utilisé la nouvelle fonctionnalité Maven 3.3.1 qui simplifie le chargement des composants principaux.

Le code et tous les échantillons peuvent être trouvés comme d'habitudeover on Github.