| ------ |
| 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 |
| |
| Introduction |
| |
| This guide is intended to assist users in developing Java plugins for |
| Maven. |
| |
| * Important Notice: {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 which takes no parameters |
| and simply displays a message on the screen when run. Along the way, we |
| will cover the basics of setting up a project to create a plugin, the |
| minimal contents of a Java mojo, and a couple ways to execute the mojo. |
| |
| ** Your First Mojo |
| |
| At its simplest, a Java mojo consists simply of a single class. There is |
| no requirement for multiple classes like EJBs, although a plugin which |
| contains a number of similar mojos is likely to use an abstract |
| superclass for the mojos to consolidate code common to all mojos. |
| |
| When processing the source tree to find mojos, {{{/plugin-tools/} <<<plugin-tools>>>}} |
| looks for classes with either <<<@Mojo>>> Java 5 annotation or "<<<goal>>>" javadoc annotation. |
| Any class with this annotation are 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 |
| { |
| 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 control how and |
| when the mojo is executed. |
| |
| * The <<<execute>>> method can throw two exceptions: |
| |
| * <<<org.apache.maven.plugin.MojoExecutionException>>> if an unexpected |
| problem occurs. Throwing this exception causes a "BUILD ERROR" message |
| to be displayed. |
| |
| * <<<org.apache.maven.plugin.MojoFailureException>>> if an expected |
| problem (such as a compilation failure) 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. Please have a look at the section |
| {{{../../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 descriptor |
| needs to have a number of settings set properly: |
| |
| *------------------+----------------------------------------------------------+ |
| |<<<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 should be set to "<<<maven-plugin>>>" | |
| *------------------+----------------------------------------------------------+ |
| |<<<dependencies>>>|A dependency must be declared to 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> |
| |
| <dependencies> |
| <dependency> |
| <groupId>org.apache.maven</groupId> |
| <artifactId>maven-plugin-api</artifactId> |
| <version>3.0</version> |
| </dependency> |
| |
| <!-- dependencies to annotations --> |
| <dependency> |
| <groupId>org.apache.maven.plugin-tools</groupId> |
| <artifactId>maven-plugin-annotations</artifactId> |
| <version>3.4</version> |
| <scope>provided</scope> |
| </dependency> |
| </dependencies> |
| </project> |
| +----+ |
| |
| ** Build Goals |
| |
| There are few goals which are defined with the <<<maven-plugin>>> |
| packaging as part of a standard build lifecycle: |
| |
| *-------------+----------------------------------------------------+ |
| |<<<compile>>>|Compiles the Java code for the plugin and builds the| |
| | |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 | |
| *-------------+----------------------------------------------------+ |
| |
| ** 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, you need to |
| configure the <<<hello-maven-plugin>>> plugin in you project: |
| |
| +----+ |
| ... |
| <build> |
| <plugins> |
| <plugin> |
| <groupId>sample.plugin</groupId> |
| <artifactId>hello-maven-plugin</artifactId> |
| <version>1.0-SNAPSHOT</version> |
| </plugin> |
| </plugins> |
| </build> |
| ... |
| +----+ |
| |
| And, you need to 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, you would 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: |
| |
| * If you need to run the latest version of a plugin installed in your 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 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> |
| +----+ |
| |
| [] |
| |
| At this point, you can run the mojo with "<<<mvn hello:sayhi>>>". |
| |
| |
| *** Attaching the Mojo to the Build Lifecycle |
| |
| You can also configure your plugin to attach specific goals to a particular |
| phase of the build lifecycle. Here is an example: |
| |
| +-----+ |
| <build> |
| <plugins> |
| <plugin> |
| <groupId>sample.plugin</groupId> |
| <artifactId>hello-maven-plugin</artifactId> |
| <version>1.0-SNAPSHOT</version> |
| <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, please |
| refer to the {{{../introduction/introduction-to-the-lifecycle.html}Build Lifecycle}} document. |
| |
| * Mojo archetype |
| |
| To create a new plugin project, you could using 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: |
| |
| * It provides hooks to allow the user to adjust the operation of the |
| plugin to suit their needs. |
| |
| * It provides 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 portion before the annotations is the description of the |
| parameter. The <<<parameter>>> annotation identifies |
| the variable as a mojo parameter. The <<<defaultValue>>> |
| parameter of the annotation defines the default value for the variable. This value can |
| include expressions which reference the project, such as |
| "<<<$\{project.version\}>>>" (more can be found in the |
| {{{http://maven.apache.org/ref/current/maven-core/apidocs/org/apache/maven/plugin/PluginParameterExpressionEvaluator.html}"Parameter Expressions" document}}). The <<<property>>> parameter can be used to allow 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 |
| |
| Configuring the parameter values for a plugin is done in a Maven |
| project within the <<<pom.xml>>> file as part of defining the |
| plugin in the project. An example of configuring a plugin: |
| |
| +-----+ |
| <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 contents 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}}. |
| |
| ** Parameter Types With One Value |
| |
| Listed below are the various types of simple variables which can be used as |
| parameters in your mojos, along with any rules on how the values in the |
| POM are interpreted. |
| |
| *** Boolean |
| |
| This includes variables typed <<<boolean>>> and <<<Boolean>>>. When reading |
| the configuration, the text "<<<true>>>" causes the parameter to be set to |
| true and all other text causes the parameter to be set to false. Example: |
| |
| +-----+ |
| /** |
| * My boolean. |
| */ |
| @Parameter |
| private boolean myBoolean; |
| +-----+ |
| |
| +-----+ |
| <myBoolean>true</myBoolean> |
| +-----+ |
| |
| *** Fixed-Point Numbers |
| |
| This includes variables typed <<<byte>>>, <<<Byte>>>, <<<int>>>, |
| <<<Integer>>>, <<<long>>>, <<<Long>>>, <<<short>>>, and <<<Short>>>. When |
| reading the configuration, the text in the XML file is converted to an |
| integer value using either <<<Integer.parseInt()>>> or the <<<valueOf()>>> |
| method of the appropriate class. This means that the strings must be valid |
| decimal integer values, consisting only of the digits 0 to 9 with an optional |
| <<<->>> in front for a negative value. Example: |
| |
| +-----+ |
| /** |
| * My Integer. |
| */ |
| @Parameter |
| private Integer myInteger; |
| +-----+ |
| |
| +-----+ |
| <myInteger>10</myInteger> |
| +-----+ |
| |
| *** Floating-Point Numbers |
| |
| This includes variables typed <<<double>>>, <<<Double>>>, <<<float>>>, and |
| <<<Float>>>. When reading the configuration, the text in the XML file is |
| converted to binary form using the <<<valueOf()>>> method for the appropriate |
| class. This means that the strings can take on any format specified in |
| section 3.10.2 of the Java Language Specification. Some samples of valid |
| values are <<<1.0>>> and <<<6.02E+23>>>. |
| |
| +-----+ |
| /** |
| * My Double. |
| */ |
| @Parameter |
| private Double myDouble; |
| +-----+ |
| |
| +-----+ |
| <myDouble>1.0</myDouble> |
| +-----+ |
| |
| *** Dates |
| |
| This includes variables typed <<<Date>>>. When reading the configuration, |
| the text in the XML file is converted using one of the following date |
| formats: "<<<yyyy-MM-dd HH:mm:ss.S a>>>" (a sample date is "2005-10-06 |
| 2:22:55.1 PM") or "<<<yyyy-MM-dd HH:mm:ssa>>>" (a sample date is "2005-10-06 |
| 2:22:55PM"). Note that parsing is done using <<<DateFormat.parse()>>> which |
| allows some leniency in formatting. If the method can parse a date and time |
| out of what is specified it will do so even if it doesn't exactly match the |
| patterns above. Example: |
| |
| +-----+ |
| /** |
| * My Date. |
| */ |
| @Parameter |
| private Date myDate; |
| +-----+ |
| |
| +-----+ |
| <myDate>2005-10-06 2:22:55.1 PM</myDate> |
| +-----+ |
| |
| *** Files and Directories |
| |
| This includes variables typed <<<File>>>. When reading the configuration, |
| the text in the XML file is used as the path to the desired file or |
| directory. If the path is relative (does not start with <<</>>> or a drive |
| letter like <<<C:>>>), the path is relative to the directory containing |
| the POM. Example: |
| |
| +-----+ |
| /** |
| * My File. |
| */ |
| @Parameter |
| private File myFile; |
| +-----+ |
| |
| +-----+ |
| <myFile>c:\temp</myFile> |
| +-----+ |
| |
| *** URLs |
| |
| This includes variables typed <<<URL>>>. When reading the configuration, the |
| text in the XML file is used as the URL. The format must follow the RFC 2396 |
| guidelines, and looks like any web browser URL |
| (<<<scheme://host:port/path/to/file>>>). No restrictions are placed on the |
| content of any of the parts of the URL while converting the URL. |
| |
| +-----+ |
| /** |
| * My URL. |
| */ |
| @Parameter |
| private URL myURL; |
| +-----+ |
| |
| +-----+ |
| <myURL>http://maven.apache.org</myURL> |
| +-----+ |
| |
| *** Plain Text |
| |
| This includes variables typed <<<char>>>, <<<Character>>>, <<<StringBuffer>>>, |
| and <<<String>>>. When reading the configuration, the text in the XML file is |
| used as the value to be assigned to the parameter. For <<<char>>> and |
| <<<Character>>> parameters, only the first character of the text is used. |
| |
| *** Enums |
| |
| Enumeration type parameters can also be used. First you need to define |
| your enumeration type and afterwards you can use the enumeration type |
| in the parameter definition: |
| |
| +-----+ |
| public enum Color { |
| GREEN, |
| RED, |
| BLUE |
| } |
| |
| /** |
| * My Enum |
| */ |
| @Parameter |
| private Color myColor; |
| +-----+ |
| |
| So lets have a look like you can use such enumeration in your pom configuration: |
| |
| +-----+ |
| <myColor>GREEN</myColor> |
| +-----+ |
| |
| You can also use elements from the enumeration type as defaultValues like the |
| following: |
| |
| +-----+ |
| public enum Color { |
| GREEN, |
| RED, |
| BLUE |
| } |
| |
| /** |
| * My Enum |
| */ |
| @Parameter(defaultValue = "GREEN") |
| private Color myColor; |
| +-----+ |
| |
| |
| ** Parameter Types With Multiple Values |
| |
| Listed below are the various types of composite objects which can be used as |
| parameters in your mojos, along with any rules on how the values in the |
| POM are interpreted. In general, the class of the object created to hold the |
| parameter value (as well as the class for each element within the parameter |
| value) is determined as follows (the first step which yields a valid class |
| is used): |
| |
| [[1]] If the XML element contains an <<<implementation>>> hint attribute, that is used |
| |
| [[2]] If the XML tag contains a <<<.>>>, try that as a fully qualified class name |
| |
| [[3]] Try the XML tag (with capitalized first letter) as a class in the same package as the mojo/object being |
| configured |
| |
| [[4]] For arrays, use the component type of the array (for example, use <<<String>>> |
| for a <<<String[]>>> parameter); for collections and maps, use the |
| class specified in the mojo configuration for the collection or map; |
| use <<<String>>> for entries in a collection and values in a map |
| |
| [] |
| |
| Once the type for the element is defined, the text in the XML file is |
| converted to the appropriate type of object |
| |
| |
| *** Arrays |
| |
| Array type parameters are configured by specifying the parameter multiple |
| times. Example: |
| |
| +-----+ |
| /** |
| * My Array. |
| */ |
| @Parameter |
| private String[] myArray; |
| +-----+ |
| |
| +-----+ |
| <myArray> |
| <param>value1</param> |
| <param>value2</param> |
| </myArray> |
| +-----+ |
| |
| *** Collections |
| |
| This category covers any class which implements <<<java.util.Collection>>> |
| such as <<<ArrayList>>> or <<<HashSet>>>. These parameters are configured by |
| specifying the parameter multiple times just like an array. Example: |
| |
| +-----+ |
| /** |
| * My List. |
| */ |
| @Parameter |
| private List myList; |
| +-----+ |
| |
| +-----+ |
| <myList> |
| <param>value1</param> |
| <param>value2</param> |
| </myList> |
| +-----+ |
| |
| For details on the mapping of the individual collection elements, see |
| {{{../mini/guide-configuring-plugins.html#Mapping_Lists}Mapping Lists}}. |
| |
| *** Maps |
| |
| This category covers any class which implements <<<java.util.Map>>> |
| such as <<<HashMap>>> but does <<not>> implement <<<java.util.Properties>>>. |
| These parameters are configured by including XML tags in the form |
| <<< <key>value</key> >>> in the parameter configuration. Example: |
| |
| +-----+ |
| /** |
| * My Map. |
| */ |
| @Parameter |
| private Map myMap; |
| +-----+ |
| |
| +-----+ |
| <myMap> |
| <key1>value1</key1> |
| <key2>value2</key2> |
| </myMap> |
| +-----+ |
| |
| *** Properties |
| |
| This category covers any map which implements <<<java.util.Properties>>>. |
| These parameters are configured by including XML tags in the form |
| <<< <property><name>myName</name> <value>myValue</value> </property> >>> |
| in the parameter configuration. Example: |
| |
| +-----+ |
| /** |
| * My Properties. |
| */ |
| @Parameter |
| private Properties myProperties; |
| +-----+ |
| |
| +-----+ |
| <myProperties> |
| <property> |
| <name>propertyName1</name> |
| <value>propertyValue1</value> |
| <property> |
| <property> |
| <name>propertyName2</name> |
| <value>propertyValue2</value> |
| <property> |
| </myProperties> |
| +-----+ |
| |
| *** Other Object Classes |
| |
| This category covers any class which does not implement <<<java.util.Map>>>, |
| <<<java.util.Collection>>>, or <<<java.util.Dictionary>>>. Example: |
| |
| +-----+ |
| /** |
| * My Object. |
| */ |
| @Parameter |
| private MyObject myObject; |
| +-----+ |
| |
| +-----+ |
| <myObject> |
| <myField>test</myField> |
| </myObject> |
| +-----+ |
| |
| Please see {{{../mini/guide-configuring-plugins.html#Mapping_Complex_Objects}Mapping Complex Objects}} for details |
| on the strategy used to configure those kind of parameters. |
| |
| * Using Setters |
| |
| You are not restricted to using private field mapping which is good if you are trying to make you Mojos resuable |
| outside the context of Maven. Using the example above we could name our private fields using the underscore |
| convention and provide setters that the configuration mapping mechanism can use. So our Mojo would look |
| like the following: |
| |
| +----+ |
| |
| public class MyQueryMojo |
| extends AbstractMojo |
| { |
| @Parameter(property="url") |
| private String _url; |
| |
| @Parameter(property="timeout") |
| private int _timeout; |
| |
| @Parameter(property="options") |
| private String[] _options; |
| |
| public void setUrl( String url ) |
| { |
| _url = url; |
| } |
| |
| public void setTimeout( int timeout ) |
| { |
| _timeout = timeout; |
| } |
| |
| public void setOptions( String[] options ) |
| { |
| _options = options; |
| } |
| |
| public void execute() |
| throws MojoExecutionException |
| { |
| ... |
| } |
| } |
| |
| +----+ |
| |
| Note the specification of the property name for each parameter which tells Maven what setter and getter to use when |
| the field's name does not match the intended name of the parameter in the plugin configuration. |
| |
| * Resources |
| |
| [[1]] {{{../../developers/mojo-api-specification.html}Mojo Documentation}}: Mojo API, Mojo annotations |
| |
| [[2]] {{{http://maven.apache.org/shared/maven-plugin-testing-harness/}Maven Plugin Testing Harness}}: Testing framework for your Mojos. |
| |
| [[3]] {{{https://codehaus-plexus.github.io/}Plexus}}: The IoC container used by Maven. |
| |
| [[4]] {{{https://codehaus-plexus.github.io/plexus-utils/}Plexus Common Utilities}}: Set of utilities classes useful for Mojo development. |
| |
| [[5]] {{{http://commons.apache.org/io/}Commons IO}}: Set of utilities classes useful for file/path handling. |
| |
| [[6]] {{{../../plugin-developers/common-bugs.html}Common Bugs and Pitfalls}}: Overview of problematic coding patterns. |
| |
| [] |