Перейти к основному содержимому

Мейвен Полиглот

· 6 мин. чтения

1. Обзор

Maven Polyglot — это набор основных расширений Maven, который позволяет писать модель POM на любом языке. Это включает в себя множество скриптов и языков разметки, отличных от XML.

Основная цель полиглота Maven — уйти от XML, так как в настоящее время он больше не используется.

В этом руководстве мы сначала начнем с понимания концепции основного расширения Maven и проекта Maven Polyglot.

Затем мы покажем, как написать расширение ядра Maven, позволяющее создавать модель POM из файла JSON, а не из знаменитого файла pom.xml.

2. Механизм загрузки расширения Maven Core

Основные расширения Maven — это подключаемые модули, загружаемые при инициализации Maven и до начала сборки проекта Maven. Эти плагины позволяют изменить поведение Maven без изменения ядра.

Например, подключаемый модуль, загружаемый при запуске, может переопределить поведение Maven по умолчанию и может считывать модель POM из другого файла, отличного от pom.xml .

Технически расширение ядра Maven — это артефакт Maven, объявленный в файле extensions.xml :

${projectDirectory}/.mvn/extensions.xml

Вот пример расширения:

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

Наконец, мы должны отметить, что для этого механизма требуется Maven 3.3.1 или выше .

3. Мейвен Полиглот

Maven Polyglot — это набор основных расширений. Каждый из них отвечает за чтение модели POM из скрипта или языка разметки.

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

В следующих разделах мы сначала рассмотрим создание проекта Maven с использованием одного из поддерживаемых языков, указанных выше.

Затем мы напишем наше расширение для поддержки POM на основе JSON.

4. Использование расширения Maven Polyglot

Одним из вариантов создания проекта Maven на основе языка, отличного от языка XML, является использование одного из артефактов, предоставляемых проектом Polyglot.

В нашем примере мы создадим проект Maven с файлом конфигурации pom.yaml .

Первый шаг — создать файл расширения ядра Maven:

${projectDirectory}/.mvn/extensions.xml

Затем мы добавим следующий контент:

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

Не стесняйтесь настраивать артефакт для выбранного вами языка в соответствии с языками, указанными выше, и проверять, доступна ли какая-либо новая версия .

Последний шаг — предоставить метаданные проекта в файле YAML :

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

Теперь мы можем запустить нашу сборку, как обычно. Например, мы можем вызвать команду:

mvn clean install

5. Использование плагина Polyglot Translate

Еще один вариант получить проект на базе одного из поддерживаемых языков — использовать плагин polyglot-translate-plugin .

Это означает, что мы можем начать с существующего проекта Maven с традиционным файлом pom.xml.

Затем мы можем преобразовать существующий проект pom.xml в желаемый полиглот с помощью плагина перевода :

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

6. Написание пользовательского расширения

Поскольку JSON не входит в число языков, предоставляемых проектом Maven Polyglot, мы реализуем простое расширение, позволяющее считывать метаданные проекта из файла JSON .

Наше расширение предоставит пользовательскую реализацию Maven ModelProcessor API, которая переопределит реализацию Maven по умолчанию.

Для этого мы изменим способ поиска файла POM и чтения и преобразования метаданных в API модели Maven.

6.1. Зависимости Maven

Мы начнем с создания проекта 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>

Здесь мы используем зависимость maven-core , так как реализуем расширение ядра . Зависимость Джексона используется для десериализации файла JSON.

А поскольку Maven использует контейнер Plexus Dependency Injection, нам нужно, чтобы наша реализация была компонентом 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. Пользовательская реализация ModelProcessor

Maven создает модель POM, вызывая метод ModelBuilder.build() , который, в свою очередь, делегирует метод ModelProcessor.read() .

Maven предоставляет реализацию DefaultModelProcessor , которая по умолчанию считывает модель POM из файла pom.xml , расположенного в корневом каталоге или указанного в качестве параметра команды.

Как следствие, мы предоставим пользовательскую реализацию ModelProcessor , которая переопределит поведение по умолчанию. Это расположение файла модели POM и способ его чтения.

Итак, давайте начнем с создания реализации 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;
}
//...
}

Аннотация @Component сделает реализацию доступной для внедрения контейнером DI (Plexus). Таким образом, когда Maven требуется внедрение ModelProcessor в ModelBuilder, контейнер Plexus предоставит эту реализацию, а не DefaultModelProcessor.

Далее мы обеспечим реализацию метода locatePom() . Этот метод возвращает файл, в котором Maven будет читать метаданные проекта.

Итак, мы вернем файл 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;
}

Следующий шаг — прочитать этот файл и преобразовать его в модель 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;
}

В этом примере мы проверяем, является ли файл файлом JSON, и используем Jackson для его десериализации в модель Maven. В противном случае это обычный XML-файл, и он будет прочитан Maven DefaultModelReader.

Нам нужно собрать расширение, и оно будет готово к использованию:

mvn clean install

6.3. Использование расширения

Чтобы продемонстрировать использование расширения, мы будем использовать веб-проект Spring Boot.

Сначала мы создадим проект Maven и удалим файл pom.xml.

Затем мы добавим расширение, которое мы реализовали выше, в ${projectDirectory}/.mvn/extensions.xml:

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

И, наконец, мы создаем pom.json со следующим содержимым:

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

Теперь мы можем запустить проект командой:

mvn spring-boot:run

7. Заключение

В этой статье мы продемонстрировали, как можно изменить поведение Maven по умолчанию с помощью проекта Maven Polyglot. Для достижения этой цели мы использовали новую функцию Maven 3.3.1, которая упрощает загрузку основных компонентов.

Код и все примеры можно найти, как обычно, на Github .