Maven, the de-facto standard build tool for Java applications over the last couple of decades, has been taught how to process build files that aren't written in XML. Known as polyglot maven, the pom.xml build file can be replaced with a plug-in that effectively knows how to synthesise one from an alternative representation using a different language. The polyglot-maven-examples repository include an Atom based file, a Scala based file, a Groovy based file, and finally a YAML based file, which looks like:

modelVersion: 4.0.0 groupId: io.takari.polyglot artifactId: yaml-project version: 0.0.1-SNAPSHOT name: 'YAML Maven Love' properties: {sisuInjectVersion: 0.0.0.M2a, teslaVersion: 3.1.0}

Each individual language can provide its own parsing and processing mechanism, and in the case of Scala or Groovy plugins can write in-line code that is executed during build time. This allows individual projects to write snippets of code that may be too simple to expose as a plug-in but not trivial to implement other than an embedded Ant script. It also allows editors with knowledge of language specific syntax to edit the files. This mixes the flexibility of Maven 1 (which supported in-line code written in a language called Jelly) along with the extensions of Maven 2 (which delegated in-line code to plug-ins). Further support is planned, such as the ability to build OSGi bundles directly from the Manifest.MF without requiring a standalone pom.xml file.

The code to implement ployglot maven has been around for a while, but it has been non-trivial to use since it required patching the Maven installation to add support for other pom.xml files. With Maven 3.3, the hooks to support such extensions allow the changes to be added to the project without requiring a specific pom.xml file. Since the release has been pushed, projects like Spring Hateoas have converted their Maven pom to a Groovy version.

Normally plug-ins are added to the pom.xml file, but where are they added if there isn't a pom.xml file in the first place? This is where a key change has been made in Maven – the addition of core extensions. By placing a .mvn folder at the root of the project, it is possible to adjust how an out-of-the-box Maven installation runs. For example, having an extensions.xml allows plug-ins to be added to the build (using the core extensions feature), which in turn can invoke the build itself. To enable the YAML build above, a snippet .mvn/extensions.xml would look like:

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

This triggers loading the YAML file and then constructing the Maven project model to enable the build to progress. The content of the file(s) can be processed using any tool; in the case of JRuby, executing a Ruby program to calculate the dependencies and set up the necessary build plug-ins.

By externalising the build process to a specific tool that knows how to generate content, whilst still being able to export the resulting compiled content (with generated pom.xml file), the pom.xml file can be reduced to just representing the runtime dependencies of the project whilst still giving compatibility for other tools that know how to resolved dependencies from the pom.xml uploaded to a repository. This gives the flexibility of Gradle or Ant whilst still encouraging standard processing tools to be exported to a plug-in extension.

It is also possible to use core extensions to add default options to the Maven command-line. For example, if the Maven project requires a larger-than-default heap size, instead of having to specify -Xmx on each invocation (or requiring the user to set up a MAVEN_OPTS or JAVA_OPTIONS variable) it is possible to have a .mvn/jvm.config file at the root level of the project which contains the arguments for the JVM:

-Xmx2048m -Xverify:none -Djava.awt.headless=true

It's also possible to set up arguments that are passed to the Maven command line options, such as invoking multi-threaded builds whilst being less verbose, by adding the following to .mvn/maven.config :

--threads 2C --quiet

Each time Maven is run from the command line, these arguments will be prepended onto the argument, making repeatable builds between developers (and servers) consistent.

The polyglot and core extensions features require Maven 3.3.1 or above, which is available for download from the maven.apache.org site.