How to Create a Maven Plugin

Introduction

With a few stumbling blocks, we eventually managed to successfully work our way through the instructions in the Guide to Developing Java Plugins.

Here we outline the steps we followed and document those issues that where not discussed in that document:

Create the skeleton for your new Plugin

We create the project for our plugin using the maven-archetype-mojo, as follows:

mvn archetype:create                              \
   -DgroupId=sample.plugin                        \
   -DartifactId=maven-hello-plugin                \
   -DarchetypeGroupId=org.apache.maven.archetypes \
   -DarchetypeArtifactId=maven-archetype-mojo

Add the Mojo for our plugin.

Here we copied the code for GreetingMojo.java into src/main/java/sample/plugin. Thus, the contents of that file are:

package sample.plugin;

import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;

/**
 * Says "Hi" to the user.
 * @goal sayhi
 */
public class GreetingMojo extends AbstractMojo
{
    public void execute() throws MojoExecutionException
    {
        getLog().info("Hello, world.");
    }
}

Note the use of JavaDoc based annotations to configure our Mojo.

Deploy our plugin

Note that we can’t deploy until we add a <distributionManagement> element to the plugin’s POM file:

<distributionManagement>
    <site>
        <id>intranet.intelliware.ca</id>
        <url>
            dav:http://intranet/internal/intware/commons
        </url>
    </site>

    <repository>
        <id>intelliwareReleases</id>
        <name>Intelliware Releases</name>
        <url>dav:http://mvnrepo.intelliware.ca/release</url>
    </repository>
    <snapshotRepository>
        <id>intelliwareSnapshots</id>
        <name>Intelliware Snapshots</name>
        <url>dav:http://mvnrepo.intelliware.ca/snapshot</url>
    </snapshotRepository>
</distributionManagement>

… and since we are using wagon for dav publishing we also need to add:

<build>
    <extensions>
        <extension>
            <groupId>org.apache.maven.wagon</groupId>
            <artifactId>wagon-webdav</artifactId>
            <version>1.0-beta-1</version>
        </extension>
    </extensions>
</build>

Now we can run “mvn deploy”.

Define pluginRepositories in your settings.xml file

Before you can use the plugin on any machine other than the one on which you have created it (and hence where it is already in your local Maven repository), you need to insure that the repository to which it has been published is listed as a pluginRepository in your settings.xml file.

Since this was the first plugin we wrote we did not have that specification yet, so we had to add the following under the profiles element:

<pluginRepositories>
  <pluginRepository>
    <id>intelliwarePluginSnapshots</id>
    <name>Intelliware Plugin Snapshots</name>
    <releases>
      <enabled>false</enabled>
      <updatePolicy>always</updatePolicy>
      <checksumPolicy>fail</checksumPolicy>
    </releases>
    <snapshots>
      <enabled>true</enabled>
      <updatePolicy>always</updatePolicy>
      <checksumPolicy>fail</checksumPolicy>
    </snapshots>
    <url>http://mvnrepo.intelliware.ca/snapshot</url>
    <layout>default</layout>
  </pluginRepository>

  <pluginRepository>
    <id>intelliwarePluginReleases</id>
    <name>Intelliware Plugin Releases</name>
    <releases>
  	<enabled>true</enabled>
  	<updatePolicy>always</updatePolicy>
  	<checksumPolicy>fail</checksumPolicy>
    </releases>
    <snapshots>
      <enabled>false</enabled>
      <updatePolicy>always</updatePolicy>
    <checksumPolicy>fail</checksumPolicy>
  </snapshots>
  <url>http://mvnrepo.intelliware.ca/release</url>
  <layout>default</layout>
  </pluginRepository>
</pluginRepositories>

Create a test client for our new plugin

We create another Maven project which we will use as a test client for our plugin, as follows:

mvn archetype:create -DgroupId=sample.plugin  \
   -DartifactId=sample-plugin-consumer

Now use the plugin

Since this Mojo requires that you are in a Maven project directory (i.e. a directoy with a POM file) to run, we can now switch to our client project directory and run the goal following the recipe “mvn <groupId>:<artifactId>:<version>:<mojo goal>”, i.e.:

mvn sample.plugin:maven-hello-plugin:1.0-SNAPSHOT:sayhi

This worked for us!

Note: If we wanted to create a Mojo that did not require a project (e.g. like an Archetype plugin) we would add the following annotation to the JavaDoc comment for our Mojo:

@requiresProject false

This is not currently documented in the Mojo API and Annotation Reference, so remember, you read it here first.

Making it easier to use the plugin

  • If you only need to run the latest release version of a plugin you can omit its version number. So just use “mvn sample.plugin:maven-hello-plugin:sayhi” to run your plugin. Note that this does NOT work for snapshot releases.
  • You can add your plugin’s groupId to the list of groupIds searched by default. To do this, you need to add the following to your ${user.home}/.m2/settings.xml file:
    <pluginGroups>
    	<pluginGroup>sample.plugin</pluginGroup>
    </pluginGroups>
    • Note that this also only works for release versions.
  • If you plugin’s artifactId is named according to the patterns “maven-$name-plugin” or “$name-maven-plugin” Maven will treat them in a special way. If no plugin matches the artifactId specified on the command line, Maven will try expanding the artifactId to these patterns in that order. So in the case of our example, you can use “mvn hello:sayhi” to run your plugin.
    • Note that this only works if you have already specified the artifact’s groupId in the <pluginGroups> element of your settings.xml file.

How to tie a Plugin’s Mojo execution to the build lifecycle

In order to invoke a plugin’s Mojo execution at a particular point in the Maven Build Lifecycle.

<build>
    <plugins>
        <plugin>
            <groupId>sample.plugin</groupId>
            <artifactId>maven-hello-plugin</artifactId>
            <executions>
                <execution>
                    <phase>pre-integration-test</phase>
                    <goals>
                        <goal>sayhi</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
    ...

If you add an “@phase” annotation to your Mojo then the Mojo will be defined to run at that phase. However, you still need to cause that Mojo to be executed by specifying it in the build configuration. For example, if we have two goals, say “pre-integration-test” and “post-integration-test” that are annotated with “@phase pre-integration-test” and “@phase post-integration-test”, respectively, then the following will cause them to be executed at their defined phases:

<build>
    <plugins>
        <plugin>
            <groupId>sample.plugin</groupId>
            <artifactId>maven-hello-plugin</artifactId>
            <executions>
                <execution>
                    <goals>
                        <goal>post-integration-test</goal>
                        <goal>pre-integration-test</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
    ...

Note that running integration-test will NOT cause the post-integration-test goal to be exectuted, you need something further in the lifecycle, like “verify”.

How to Get Help for a Plugin

Maven has a help plugin with a describe goal that will display information on the Mojos defined in a plugin.

The following will list all the Mojos defined for a plugin:

mvn help:describe                   \
   -DgroupId=sample.plugin          \
   -DartifactId=maven-hello-plugin  \
   -Dfull=true

or, you can use the format:

mvn help:describe                             \
   -Dplugin=sample.plugin:maven-hello-plugin  \
   -Dfull=true

or, simply:

mvn help:describe -Dplugin=hello -Dfull=true

If you want information only for a specific Mojo of a plugin, you can use either:

mvn help:describe                   \
   -DgroupId=sample.plugin          \
   -DartifactId=maven-hello-plugin  \
   -Dmojo=sayhi                     \
   -Dfull=true

or:

mvn help:describe -Dplugin=hello -Dfull=true -Dmojo=sayhi

References

It's only fair to share...
Share on FacebookGoogle+Tweet about this on TwitterShare on LinkedIn

Leave a Reply