Contents:
This page will take a stab on announcing breaking changes with latest upcoming Maven versions, and to discuss "best practices" for building Maven Plugins. This page assumes that reader know the general "best practices" for Java Projects (as Maven Plugins are basically Java projects).
Maven Project resources are limited we cannot cover "backward compatilibty" across two major versions. Hence, Maven 2 support is about to be removed. Below is the summary of breaking changes, that will happen in upcoming Maven 3.9.0 and 4.0.0:
org.codehaus.plexus:plexus-utils
artifact is not anymore "auto injected" (auto provided) to plugins classpath. Maven 2 did provide this dependency from Maven Core automatically to plugins and extensions, then Maven 3.0.0-alpha-3 added this feature to ease plugins transition MNG-3819. This is not the case anymore. Plugin developers have to prepare for this change. Backward compatible change is really simple: just declare dependency on plexus-utils
in compile
scope, if your plugin does use classes from it, but does not have it declared (or have it in provided
scope).org.apache.maven:maven-compat
(the Maven2 compatibility layer), it's really time to look for alternatives. Note: this dependency in test
scope is "acceptable" and actually required by some testing frameworks (see below). This module is not removed in 3.9.0, nor in first releases of 4.0.x, but as part of Maven 2 backward compatibility layer, is to be removed somewhere in future.Maven 4.0.0 brings some new things in the play:
Maven Plugins are meant to be invoked by and run within Maven. Hence, one can draw a parallel between them and, for example, Java Servlets, where Servlet Container "provides" some dependencies to implementations. In this aspect: Maven is also a Container, container for Maven Plugins. Maven provides to plugins the "Maven API" classloader as parent, but to build a plugin, you still need to declare some depedencies.
A Maven Plugin aside of usually "Java project" things like Java source/target/release version needs to declare several extra things:
maven-plugin
maven-plugin-plugin
version (as otherwise you depend on version that Maven brings, your build is not reproducible).project/prerequisites/maven
field.provided
scope. Recent maven-plugin-plugin
versions will warn you about this.maven-plugin-api
and org.apache.maven.plugin-tools:maven-plugin-annotations
(to be able to annotate your Mojos, all the older ways like Javadoc taglets are being deprecated). We can already see, that we have at least two repeating versions, so they are "potential" properties to lessen duplication:
mavenVersion
to declare Maven version we build against (and use it in prerequisites and dependency declarations)mavenPluginToolsVersion
to declare Maven Plugin Tools version, once as dependency version for org.apache.maven.plugin-tools:maven-plugin-annotations
dependency and once for org.apache.maven.plugins:maven-plugin-plugin
build plugin (and optionally for org.apache.maven.plugins:maven-plugin-report-plugin)
.Hence, a "minimal" Maven Plugin POM (showing elements related to Maven Plugins only) should have elements like this:
<prerequisites>
<maven>${mavenVersion}</maven>
</prerequisites>
<properties>
<mavenVersion>3.6.3</mavenVersion>
<mavenPluginToolsVersion>3.7.0</mavenPluginToolsVersion>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-plugin-api</artifactId>
<version>${mavenVersion}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.maven.plugin-tools</groupId>
<artifactId>maven-plugin-annotations</artifactId>
<version>${mavenPluginToolsVersion}</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-plugin-plugin</artifactId>
<version>${mavenPluginToolsVersion}</version>
</plugin>
</plugins>
</build>
Notes:
maven-clean-plugin
is. Still, "latest stable" it too high constraint as well. Best middle ground is something like "latest patch release of one/two minor versions minus from current stable" or some similar policy (as of writing: 3.8.7 is latest stable, hence 3.6.3 is sane middle ground). Also, do not forget that Maven versions since 3.3 were all Java 7, just like current latest stable 3.8.7 is!org.codehaus.plexus:plexus-utils
for plugins as well, or in other words, plugins did not had to to declare plexus-utils
as dependency, it was "just there" (or they did, but in provided
scope). Maven 3.x continued doing this as part of "backward compatibility" with Maven 2.x line, but this will not happen anymore with Maven 3.9 and 4.0! If your plugin uses plexus-utils
, but does not have it declared as compile
scoped dependency, it will fail in Maven 3.9.0 or later.org.apache.maven.shared
instead.Then you can enlist your other (non-Maven) dependencies as well.
Testing Maven Plugins is not trivial thing, given they are Maven Components, but not plain Eclipse Sisu or Codehaus Plexus components, but rather the plugin descriptor needs to be "translated" and installed into (any of two) container, plus the existing components in Maven Plugin JAR, if any. Hence, simplest is to use some existing frameworks for testing Maven Plugins.
This section is more like a collection of links/pointers, so below is a list of some documentation and frameworks:
Alternative frameworks supporting Junit5 or taking alternate approach: