Maven Polyglot – Maven Polyglot

最后修改: 2018年 10月 7日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

Maven Polyglot is a set of Maven core extensions that allows the POM model to be written in any language. This includes many scripts and markup languages other than XML.

Maven Polyglot是一套Maven的核心扩展,可以用任何语言编写POM模型。这包括许多脚本和XML以外的标记语言。

The primary goal of Maven polyglot is to escape from XML as it’s no longer the go-to language nowadays.

Maven polyglot的主要目标是摆脱XML,因为它不再是现今的首选语言。

In this tutorial, we’ll first start by understanding the Maven core extension concept and the Maven Polyglot project.

在本教程中,我们首先要了解Maven核心扩展概念和Maven Polyglot项目。

Then, we’ll show how to write a Maven core extension that allows the POM model to be constructed from a JSON file rather than the famous pom.xml.

然后,我们将展示如何编写一个Maven核心扩展,让POM模型从JSON文件而非著名的pom.xml.构建。

2. Maven Core Extension Loading Mechanism

2.Maven核心扩展加载机制

The Maven core extensions are plugins loaded at Maven initialization and before the Maven project build start. These plugins allow changing Maven behavior without changing the core.

Maven核心扩展是在Maven初始化时和Maven项目构建开始前加载的插件。这些插件可以在不改变核心的情况下改变Maven行为。

For example, a plugin loaded at startup can override the Maven default behavior and can read the POM model from another file than the pom.xml.

例如,启动时加载的插件可以覆盖Maven的默认行为,可以从另一个文件而不是pom.xml中读取POM模型。

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

从技术上讲,Maven核心扩展是一个在extensions.xml文件中声明的Maven工件:

${projectDirectory}/.mvn/extensions.xml

Here’s an example of an extension:

这里有一个扩展的例子。

<?xml version="1.0" encoding="UTF-8"?>
<extensions>
    <extension>
        <groupId>com.baeldung.maven.polyglot</groupId>
        <artifactId>maven-polyglot-json-extension</artifactId>
        <version>1.0-SNAPSHOT</version>
    </extension>
</extensions>

Finally, we need to note that this mechanism requires Maven 3.3.1 or higher.

最后,我们需要注意,该机制需要Maven 3.3.1或更高版本

3. Maven Polyglot

3.Maven Polyglot[/strong

Maven Polyglot is a collection of core extensions. Each one of these is responsible for reading the POM model from a script or markup language.

Maven Polyglot是一个核心扩展的集合。每个扩展都负责从脚本或标记语言中读取POM模型。

Maven Polyglot provide extensions for the following languages:

Maven Polyglot为以下语言提供扩展。

+-----------+-------------------+--------------------------------------+
| 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                    |
+-----------+-------------------+--------------------------------------+

In the next sections, we’ll first have a look at building a Maven project using one of the supported languages above.

在接下来的章节中,我们将首先看看如何使用上述支持的语言之一构建Maven项目。

Then, we’ll write our extension to support a JSON-based POM.

然后,我们将编写我们的扩展来支持基于JSON的POM。

4. Using a Maven Polyglot Extension

4.使用Maven的多语言扩展

One option to build a Maven project based on a different language than XML is to use one of the artifacts provided by the Polyglot project.

构建基于不同语言而非XML的Maven项目的一个选择是使用Polyglot项目提供的一个工件。

In our example, we’ll create a Maven project with a pom.yaml configuration file.

在我们的例子中,我们将创建一个带有pom.yaml配置文件的Maven项目

The first step is to create the Maven core extension file:

第一步是创建Maven核心扩展文件。

${projectDirectory}/.mvn/extensions.xml

Then we’ll add the following content:

然后我们将添加以下内容。

<?xml version="1.0" encoding="UTF-8"?>
<extensions>
    <extension>
        <groupId>io.takari.polyglot</groupId>
        <artifactId>polyglot-yaml</artifactId>
        <version>0.3.1</version>
    </extension>
</extensions>

Feel free to adjust the artifactId to your chosen language accordingly to the languages above and to check if any new version is available.

请随意将artifactId调整为您所选择的语言,与上述语言相对应,并检查是否有任何新版本可用。

The last step is to provide the project metadata in the YAML file:

最后一步是在YAML文件中提供项目元数据。

modelVersion: 4.0.0
groupId: com.baeldung.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}

Now we can run our build as we usually do. For example, we can invoke the command:

现在我们可以像通常那样运行我们的构建。例如,我们可以调用命令。

mvn clean install

5. Using the Polyglot Translate Plugin

5.使用Polyglot翻译插件

Another option to obtain a project based on one of the supported languages is to use the polyglot-translate-plugin.

获得基于支持的语言之一的项目的另一个选择是使用polyglot-translate-plugin.

This means we can start from an existing Maven project with a traditional pom.xml.

这意味着我们可以从一个现有的Maven项目开始,用传统的pom.xml.

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

然后,我们可以通过使用翻译插件将现有的pom.xml项目转换为所需的polyglot

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

6. Writing a Custom Extension

6.编写一个自定义扩展

As JSON is not one of the languages provided by the Maven Polyglot project, we’ll implement a simple extension that allows reading project metadata from a JSON file.

由于JSON不是Maven Polyglot项目提供的语言之一,我们将实现一个简单的扩展,可以从JSON文件中读取项目元数据

Our extension will provide a custom implementation of the Maven ModelProcessor API which will override the Maven default implementation.

我们的扩展将提供Maven ModelProcessor API的定制实现,它将覆盖Maven的默认实现。

To achieve this, we’ll to change the behavior of how to locate the POM file and how to read and transform the metadata to the Maven Model API.

为了实现这一目标,我们将改变如何定位POM文件以及如何读取元数据并将其转换为Maven Model API的行为。

6.1. Maven Dependencies

6.1.Maven的依赖性

We’ll start by creating a Maven project with the following dependencies:

我们首先要创建一个Maven项目,其依赖关系如下。

<dependency>
    <groupId>org.apache.maven</groupId>
    <artifactId>maven-core</artifactId>
    <version>3.5.4</version>
    <scope>provided</scope>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.13.0</version>
</dependency>

Here we use the maven-core dependency as we’ll implement a core extension. The Jackson dependency is used to deserialize the JSON file.

这里我们使用maven-core依赖项,因为我们将实现一个核心扩展Jackson依赖项被用来反序列化JSON文件。

And as Maven uses the Plexus Dependency Injection container, we need our implementation to be a Plexus component. So we need this plugin to generate the Plexus metadata:

由于Maven使用Plexus依赖注入容器,我们需要将我们的实现变成一个Plexus组件。所以我们需要这个插件来生成Plexus元数据。

<plugin>
    <groupId>org.codehaus.plexus</groupId>
    <artifactId>plexus-component-metadata</artifactId>
    <version>1.7.1</version>
    <executions>
        <execution>
            <goals>
                <goal>generate-metadata</goal>
            </goals>
        </execution>
    </executions>
</plugin>

6.2. The Custom ModelProcessor Implementation

6.2.自定义ModelProcessor实现

Maven constructs the POM model by invoking the ModelBuilder.build() method which in turn delegates to the ModelProcessor.read() method.

Maven通过调用ModelBuilder.build()方法来构建POM模型,该方法又委托给ModelProcessor.read()方法。

Maven provides a DefaultModelProcessor implementation which by default reads the POM model from a pom.xml file located at the root directory or specified as a parameter command.

Maven提供了一个DefaultModelProcessor实现,它默认从位于根目录的pom.xml文件中读取POM模型,或者作为参数命令指定。

In consequence, we’ll provide a custom ModelProcessor implementation which will override the default behavior. That is the location of the POM model file location and how to read it.

因此,我们将提供一个自定义的ModelProcessor实现,它将覆盖默认行为。那就是POM模型文件的位置以及如何读取它。

So let’s start by creating a CustomModelProcessor implementation and mark it as a Plexus component:

因此,让我们先创建一个CustomModelProcessor实现,并将其标记为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<String, ?> options) throws IOException, ModelParseException {
        return null;
    }
    //...
}

The @Component annotation will make the implementation available for injection by the DI container (Plexus). So, when Maven needs a ModelProcessor injection in the ModelBuilder, the Plexus container will provide this implementation and not the DefaultModelProcessor.

@Component注解将使DI容器(Plexus)可以注入实现。因此,当Maven需要在ModelBuilder中注入ModelProcessor时,Plexus容器将提供这个实现,而不是DefaultModelProcessor。

Next, we’ll provide the implementation for the locatePom() method. This method returns the file where Maven will read the project metadata.

接下来,我们将提供locatePom()方法的实现。该方法返回Maven将读取项目元数据的文件。

So we’ll return a pom.json file if it exists, otherwise, the pom.xml as we usually do:

所以我们将返回一个pom.json文件,如果它存在的话,否则就像我们通常做的那样,返回pom.xml

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

The next step is to read this file and transform it to the Maven Model. This is achieved by the read() method:

下一步是读取该文件并将其转换为Maven模型。这可以通过read()方法实现:

@Requirement
private ModelReader modelReader;

@Override
public Model read(InputStream input, Map<String, ?> 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;
}

In this example, we check if the file is a JSON file and we use the Jackson to deserialize it to a Maven Model. Otherwise, it’s a normal XML file, and it will be read by the Maven DefaultModelReader.

在这个例子中,我们检查文件是否是JSON文件,然后用Jackson将其反序列化为Maven的Model.,否则就是普通的XML文件,它将被Maven的DefaultModelReader读取。

We need to build the extension, and it will be ready for use:

我们需要建造扩展部分,然后就可以使用了。

mvn clean install

6.3. Using the Extension

6.3.使用该扩展

To demonstrate the use of the extension, we’ll use a Spring Boot Web project.

为了演示该扩展的使用,我们将使用一个Spring Boot Web项目。

First, we’ll create a Maven project, and delete the pom.xml.

首先,我们将创建一个Maven项目,并删除pom.xml.

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

然后,我们将在${projectDirectory}/.mvn/extensions.xml中添加上面实现的扩展:

<?xml version="1.0" encoding="UTF-8"?>
<extensions>
    <extension>
        <groupId>com.baeldung.maven.polyglot</groupId>
        <artifactId>maven-polyglot-json-extension</artifactId>
        <version>1.0-SNAPSHOT</version>
    </extension>
</extensions>

And finally we create the pom.json with the following content:

最后我们创建pom.json,内容如下。

{
  "modelVersion": "4.0.0",
  "groupId": "com.baeldung.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"
      }
    ]
  }
}

We can now run the project with the command:

现在我们可以用命令运行该项目。

mvn spring-boot:run

7. Conclusion

7.结论

In this article, we’ve demonstrated how we can change the default Maven behavior through the Maven Polyglot project. To achieve this goal we have used the new Maven 3.3.1 feature that simplifies the core components loading.

在本文中,我们演示了如何通过Maven Polyglot项目改变默认的Maven行为。为实现这一目标,我们使用了Maven 3.3.1的新功能,简化了核心组件的加载。

The code and all the samples can be found as usual over on Github.

代码和所有样本可以像往常一样在Github上找到over