blob: d899f97a9e89cd9c6888e35a92d8cb89afa58ae0 [file] [log] [blame]
------
Guide to Developing Java Plugins
------
Bob Allison
Vincent Siveton
Olivier Lamy
------
2013-01-02
------
~~ Licensed to the Apache Software Foundation (ASF) under one
~~ or more contributor license agreements. See the NOTICE file
~~ distributed with this work for additional information
~~ regarding copyright ownership. The ASF licenses this file
~~ to you under the Apache License, Version 2.0 (the
~~ "License"); you may not use this file except in compliance
~~ with the License. You may obtain a copy of the License at
~~
~~ http://www.apache.org/licenses/LICENSE-2.0
~~
~~ Unless required by applicable law or agreed to in writing,
~~ software distributed under the License is distributed on an
~~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
~~ KIND, either express or implied. See the License for the
~~ specific language governing permissions and limitations
~~ under the License.
~~ NOTE: For help with the syntax of this file, see:
~~ http://maven.apache.org/doxia/references/apt-format.html
Guide to Developing Java Plugins
This guide is intended to assist users in developing Java plugins for
Maven.
%{toc|fromDepth=2}
* Important Notice
{{{../mini/guide-naming-conventions.html}<<Plugin Naming Convention and Apache Maven Trademark>>}}
You will typically name your plugin <<<<yourplugin>-maven-plugin>>>.
Calling it <<<maven-<yourplugin>-plugin>>> (note "Maven" is at the beginning
of the plugin name) is <<strongly discouraged>> since it's a
<<reserved naming pattern for official Apache Maven plugins maintained by the Apache Maven team>>
with groupId <<<org.apache.maven.plugins>>>.
Using this naming pattern is an infringement of the Apache Maven Trademark.
* Your First Plugin
In this section we will build a simple plugin with one goal that takes no parameters
and displays a message on the screen when run. Along the way, we
will cover setting up a project to create a plugin, the
minimal contents of a Java mojo which will define goal code, and a couple ways to execute the mojo.
** Your First Mojo
At its simplest, a Java mojo consists simply of a single class representing one plugin's goal.
When processing the source tree to find mojos, {{{/plugin-tools/} <<<plugin-tools>>>}}
looks for classes with the <<<@Mojo>>> annotation.
Any class with this annotation is included in the plugin configuration file.
*** A Simple Mojo
Listed below is a simple mojo class which has no parameters. This is
about as simple as a mojo can be. After the listing is a description
of the various parts of the source.
+---+
package sample.plugin;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugins.annotations.Mojo;
/**
* Says "Hi" to the user.
*
*/
@Mojo(name = "sayhi")
public class GreetingMojo extends AbstractMojo
{
@Override
public void execute() throws MojoExecutionException
{
getLog().info("Hello, world.");
}
}
+---+
* The class <<<org.apache.maven.plugin.AbstractMojo>>> provides most of the
infrastructure required to implement a mojo except for the
<<<execute>>> method.
* The annotation "<<<@Mojo>>>" is required and controls how and
when the mojo is executed.
* The <<<execute>>> method can throw <<<org.apache.maven.plugin.MojoExecutionException>>> if a problem occurs.
Throwing this exception causes a <<<BUILD FAILURE>>> message to be displayed.
* The <<<getLog>>> method (defined in <<<AbstractMojo>>>) returns a
log4j-like logger object which allows plugins to create messages at levels
of "debug", "info", "warn", and "error". This logger is the accepted means
to display information to the user. See
{{{../../plugin-developers/common-bugs.html#Retrieving_the_Mojo_Logger}Retrieving the Mojo Logger}} for a hint on
its proper usage.
[]
All Mojo annotations are described by the {{{../../developers/mojo-api-specification.html#The_Descriptor_and_Annotations}Mojo API Specification}}.
** Project Definition
Once the mojos have been written for the plugin, it is time to
build the plugin. To do this properly, the project's pom.xml
must set these things:
*------------------+----------------------------------------------------------+
|<<<groupId>>> |This is the group ID for the plugin, and should match the |
| |common prefix to the packages used by the mojos. |
*------------------+----------------------------------------------------------+
|<<<artifactId>>> |This is the name of the plugin. |
*------------------+----------------------------------------------------------+
|<<<version>>> |This is the version of the plugin. |
*------------------+----------------------------------------------------------+
|<<<packaging>>> |This must be set to "<<<maven-plugin>>>" |
*------------------+----------------------------------------------------------+
|<<<dependencies>>>|A dependency must be declared on the Maven Plugin Tools |
| |API to resolve "<<<AbstractMojo>>>" and related classes |
*------------------+----------------------------------------------------------+
Listed below is an illustration of the sample mojo project's pom with the parameters set as described in the above table:
+----+
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>sample.plugin</groupId>
<artifactId>hello-maven-plugin</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>maven-plugin</packaging>
<name>Sample Parameter-less Maven Plugin</name>
<properties>
<maven-plugin-tools.version>$context.get("version.maven-plugin-tools")</maven-plugin-tools.version>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-plugin-api</artifactId>
<version>3.9.9</version>
<scope>provided</scope>
</dependency>
<!-- dependency on annotations -->
<dependency>
<groupId>org.apache.maven.plugin-tools</groupId>
<artifactId>maven-plugin-annotations</artifactId>
<version>${esc.dollar}{maven-plugin-tools.version}</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-plugin-plugin</artifactId>
<version>${esc.dollar}{maven-plugin-tools.version}</version>
<executions>
<execution>
<id>help-mojo</id>
<goals>
<!-- good practice is to generate help mojo for plugin -->
<goal>helpmojo</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</pluginManagement>
</build>
<reporting>
<plugins>
<!-- automatically generate plugin documentation when running `mvn site` -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-plugin-report-plugin</artifactId>
<version>${esc.dollar}{maven-plugin-tools.version}</version>
</plugin>
</plugins>
</reporting>
</project>
+----+
** Building a Plugin
There are few plugin goals bound to the standard build lifecycle
defined with the <<<maven-plugin>>> packaging:
*-------------+----------------------------------------------------+
|<<<compile>>>|Compiles the Java code for the plugin |
*-------------+----------------------------------------------------+
|<<<process-classes>>>|Extracts data to build the {{{/ref/current/maven-plugin-api/plugin.html}plugin descriptor}}|
*-------------+----------------------------------------------------+
|<<<test>>> |Runs the plugin's unit tests |
*-------------+----------------------------------------------------+
|<<<package>>>|Builds the plugin jar |
*-------------+----------------------------------------------------+
|<<<install>>>|Installs the plugin jar in the local repository |
*-------------+----------------------------------------------------+
|<<<deploy>>> |Deploys the plugin jar to the remote repository |
*-------------+----------------------------------------------------+
For more details, you can look at
{{{/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_maven-plugin_packaging} detailed bindings for <<<maven-plugin>>> packaging}}.
** Executing Your First Mojo
The most direct means of executing your new plugin is to specify the
plugin goal directly on the command line. To do this,
configure the <<<hello-maven-plugin>>> plugin in the project:
+----+
<project>
...
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>sample.plugin</groupId>
<artifactId>hello-maven-plugin</artifactId>
<version>1.0-SNAPSHOT</version>
</plugin>
</plugins>
</pluginManagement>
</build>
...
</project>
+----+
Then on the command line specify a fully-qualified goal in the form of:
------
mvn groupId:artifactId:version:goal
------
For example, to run the simple mojo in the sample plugin, enter
"<<<mvn sample.plugin:hello-maven-plugin:1.0-SNAPSHOT:sayhi>>>" on the
command line.
<<Tips>>: <<<version>>> is not required to run a standalone goal.
*** Shortening the Command Line
There are several ways to reduce the amount of required typing:
* To run the latest version of a plugin installed in the local
repository, you can omit its version number. So just use
"<<<mvn sample.plugin:hello-maven-plugin:sayhi>>>" to run your plugin.
* You can assign a shortened prefix to your plugin, such as <<<mvn hello:sayhi>>>.
This is done automatically if you follow the convention of using
<<<$\{prefix\}-maven-plugin>>> (or <<<maven-$\{prefix\}-plugin>>> if the plugin is
part of the Apache Maven project). You may also assign one through additional
configuration. For more information, see
{{{../introduction/introduction-to-plugin-prefix-mapping.html} Introduction to Plugin Prefix Mapping}}.
* Finally, you can also add your plugin's group ID to the list of group IDs
searched by default. To do this, add the following to
your <<<$\{user.home\}/.m2/settings.xml>>> file:
+----+
<pluginGroups>
<pluginGroup>sample.plugin</pluginGroup>
</pluginGroups>
+----+
[]
At this point, you can run the mojo with "<<<mvn hello:sayhi>>>".
*** Attaching the Mojo to the Build Lifecycle
You can also configure the plugin to attach specific goals to a particular
phase of the build lifecycle. Here is an example:
+-----+
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>sample.plugin</groupId>
<artifactId>hello-maven-plugin</artifactId>
<version>1.0-SNAPSHOT</version>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<plugin>
<groupId>sample.plugin</groupId>
<artifactId>hello-maven-plugin</artifactId>
<executions>
<execution>
<phase>compile</phase>
<goals>
<goal>sayhi</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
+-----+
This causes the simple mojo to be executed whenever Java code is compiled.
For more information on binding a mojo to phases in the lifecycle,
see the {{{../introduction/introduction-to-the-lifecycle.html}Build Lifecycle}} document.
* Mojo archetype
To create a new plugin project, you can use the Mojo
{{{../introduction/introduction-to-archetypes.html}archetype}} with the following command line:
-----
mvn archetype:generate \
-DgroupId=sample.plugin \
-DartifactId=hello-maven-plugin \
-DarchetypeGroupId=org.apache.maven.archetypes \
-DarchetypeArtifactId=maven-archetype-plugin
-----
* Parameters
It is unlikely that a mojo will be very useful without parameters.
Parameters provide a few very important functions:
* They provide hooks to allow the user to adjust the operation of the
plugin to suit their needs.
* They provide a means to easily extract the value of elements from
the POM without the need to navigate the objects.
[]
** Defining Parameters Within a Mojo
Defining a parameter is as simple as creating an instance variable
in the mojo and adding the proper annotations. Listed below is an
example of a parameter for the simple mojo:
+-----+
/**
* The greeting to display.
*/
@Parameter(property = "sayhi.greeting", defaultValue = "Hello World!" )
private String greeting;
+-----+
The Javadoc comment is the description of the
parameter. The <<<@Parameter>>> annotation identifies
the variable as a mojo parameter. The <<<defaultValue>>>
element defines the default value for the parameter. This value can
include expressions which reference the project, such as
"<<<$\{project.version\}>>>". (More can be found in the
{{{/ref/current/maven-core/apidocs/org/apache/maven/plugin/PluginParameterExpressionEvaluator.html}"Parameter Expressions" document.}})
The <<<property>>> element enables configuration
of the mojo parameter from the command line by referencing a system property that the user sets
via the <<<-D>>> option.
** Configuring Parameters in a Project
Each Maven project can configure the plugins it uses
in the <<<pluginManagement>>> section of the pom.xml. For example:
+-----+
<plugin>
<groupId>sample.plugin</groupId>
<artifactId>hello-maven-plugin</artifactId>
<version>1.0-SNAPSHOT</version>
<configuration>
<greeting>Welcome</greeting>
</configuration>
</plugin>
+-----+
In the configuration section, the element name
("<<<greeting>>>") is the parameter name and the content of
the element ("<<<Welcome>>>") is the value to be assigned to
the parameter.
<<Note>>: More details can be found in the
{{{../mini/guide-configuring-plugins.html}Guide to Configuring Plugins}}.
* Using Setters
You are not restricted to using private field mapping which is helpful
if you are trying to make your Mojos reusable outside the context of Maven.
In the example above, we could define public setter methods that the configuration mapping mechanism can use.
You can also add an <<<@Parameter>>> annotation on the setter method (from version 3.7.0 of `plugin-tools`)
So the Mojo would look like the following:
+----+
public class MyQueryMojo extends AbstractMojo {
// provide name for non matching field and setter name
@Parameter(name = "url", property = "url")
private String url;
@Parameter(property = "timeout")
private int timeout;
private String option0;
private String option1;
public void setUrl(String url) {
this.url = url;
}
public void setTimeout(int timeout) {
this.timeout = timeout;
}
@Parameter(property = "options")
public void setOptions(String[] options) {
// we can do something more with provided parameter
this.option0 = options[0];
this.option1 = options[1];
}
@Override
public void execute() throws MojoExecutionException {
...
}
}
+----+
The property annotation for each parameter tells Maven which setter and getter to use when
the field's name does not match the name of the parameter in the plugin configuration.
* Plugin Documentation
To make it easy for others to use your plugin, you should document it. See the {{{../development/guide-plugin-documentation.html}Plugin Documentation Guide}}
for more information.
* Resources
[[1]] {{{../../developers/mojo-api-specification.html}Mojo Documentation}}: Mojo API, Mojo annotations
[[2]] {{{/shared/maven-plugin-testing-harness/}Maven Plugin Testing Harness}}: Testing framework for your Mojos.
[[3]] {{{https://eclipse.dev/sisu/index.html}Eclipse Sisu}}: The IoC container used by Maven 3.
[[4]] {{{../../maven-jsr330.html}Maven & JSR 330}}: How to use JSR 330 in Plugins
[[5]] {{{../../plugin-developers/common-bugs.html}Common Bugs and Pitfalls}}: Overview of problematic coding patterns.
[]