How to Use Aether in Maven Plugins

By Benjamin Bentmann

2 minute read time

When developing plugins for Maven 3.0, plugin developers that need to perform dependency resolution have a choice: they can continue to use the Maven 2.x API, or they can use the new Maven 3 API, which uses Aether. In this post, I'm going to walk through some API features now available to plugin developers in Aether.

If your plugin needs to be compatible with Maven 2.x, look at the sources of Maven Dependency Plugin. This example provides a sophisticated example of using the Maven 2.x dependency resolution API. But if legacy Maven support is of no concern to you, read on and see how the Maven 3.x API handles the job.

Aether Plugin Dependencies

To use the new Maven 3.x Plugin API, add the following dependencies to your plugin project's POM:

<script src="https://gist.github.com/777716.js?file=aether-dependencies.xml"></script>

The dependency on maven-plugin-api shouldn't be surprising - the more interesting bits are aether-api and aether-util. Depending on your use case, the latter dependency might not be required for your plugin given aether-util is just a collection of utility classes. For our example, however, it will be handy to have org.sonatype.aether.util.artifact.DefaultArtifact around.

Mojo Parameters

Now that the plugin build path is set up, we can continue to add some parameters to our plugin that will grab the repository system:

<script src="https://gist.github.com/777719.js?file=MyMojo-aether-parameters.java" ></script>

Contrary to Maven 2.x, a single component of type RepositorySystem is sufficient for all resolution work. This repository system generally takes a request bean as input and hands back a result bean. When performing multiple repository operations, some inputs tend to be the same, like the local repository, the offline mode, proxies etc. These configuration values are represented by the RepositorySystemSession.

The remote repositories to resolve from are always specific to a certain operation. For our example, we're going to use the remote plugin repositories of the current project. Alternatively, the expression $\{project.remoteProjectRepositories\} is available to grab the project dependency repositories. Which set of remote repositories to use depends on the artifacts the plugin will resolve. Artifacts that are compile/runtime/test dependencies of a project need to be resolved from $\{project.remoteProjectRepositories\}. Plugins or other artifacts that merely support the build need to be resolved from $\{project.remotePluginRepositories\}.

Mojo Execution

Equipped with the plugin parameters shown in the previous section, we can start to do some real work with project dependencies:

<script src="https://gist.github.com/777724.js?file=gistfile1.java" ></script>

This code snippet resolves a single artifact hard-coded here for the sake of conciseness. By using other methods of the repoSystem transitive resolution or version query can also be performed.

Tip: To help with the common task of transitively resolving project dependencies, the maven-core artifact provides the component org.apache.maven.project.ProjectDependenciesResolver.

A complete plugin project ready to run and play with can be found in our Git repo at https://github.com/sonatype/aether-demo-maven-plugin.

A final note to avoid confusion when experimenting with the new API: Unlike the Maven 2.x API, Artifact instances in Aether are immutable. As such, the result of a resolution operation returns new Artifact instances. That is why it is essential that the log statement above uses result.getArtifact().getFile() and not artifact.getFile().

Picture of Benjamin Bentmann

Written by Benjamin Bentmann

Benjamin is a Software Developer at Sonatype, based in Germany. His specialties include Java, C++, MFC, and .NET.

Tags