In Maven plug-ins are configured by specifying a configuration element where the child elements of the configuration element are mapped to fields, or setters, inside your Mojo (remember that a plug-in consists of one or more Mojos where a Mojo maps to a goal). Say, for example, we had a Mojo that performed a query against a particular URL, with a specified timeout and list of options. The Mojo might look like the following:
public class MyQueryMojo
extends AbstractMojo
{
/**
* @parameter
*/
private String url;
/**
* @parameter
*/
private int timeout;
/**
* @parameter
*/
private String[] options;
public void execute()
throws MojoExecutionException
{
...
}
}
To configure the Mojo from your POM with the desired URL, timeout and options you might have something like the following:
<project>
...
<build>
<plugins>
<plugin>
<artifactId>maven-myquery-plugin</artifactId>
<version>1.0</version>
<configuration>
<url>http://www.foobar.com/query</url>
<timeout>10</timeout>
<options>
<option>one</option>
<option>two</option>
<option>three</option>
</options>
</configuration>
</plugin>
</plugins>
</build>
...
</project>
As you can see the elements in the configuration match the names of the fields in the Mojo. The configuration mechanism Maven employs is very similar to the way XStream works where elements in XML are mapped to objects. So from the example above you can see that the mapping is pretty straight forward the url element maps to the url field, the timeout element maps to the timeout field and the options element maps to the options field. The mapping mechanism can deal with arrays by inspecting the type of the field and determining if a suitable mapping is possible.
Mapping complex types is also fairly straight forward in Maven so let's look at a simple example where we are trying to map a configuration for Person object. The configuration element might look like the following:
... <configuration> <person> <firstName>Jason</firstName> <lastName>van Zyl</lastName> </person> </configuration> ...
The rules for mapping complex objects are as follows:
... <configuration> <person implementation="com.mycompany.mojo.query.SuperPerson"> <firstName>Jason</firstName> <lastName>van Zyl</lastName> </person> </configuration> ...
The configuration mapping mechanism can easily deal with most collections so let's go through a few examples to show you how it's done:
Mapping lists works in much the same way as mapping to arrays where you a list of elements will be mapped to the List. So if you have a mojo like the following:
public class MyAnimalMojo
extends AbstractMojo
{
/**
* @parameter
*/
private List animals;
public void execute()
throws MojoExecutionException
{
...
}
}
Where you have a field named animals then your configuration for the plug-in would look like the following:
<project>
...
<build>
<plugins>
<plugin>
<artifactId>maven-myanimal-plugin</artifactId>
<version>1.0</version>
<configuration>
<animals>
<animal>cat</animal>
<animal>dog</animal>
<animal>aardvark</animal>
</animals>
</configuration>
</plugin>
</plugins>
</build>
...
</project>
Where each of the animals listed would be entries in the animals field. If there is no Animal class present then the field is assume to be of type java.lang.String.
In the same way, you could define maps like the following:
...
/**
* My Map.
*
* @parameter
*/
private Map myMap;
...
...
<configuration>
<myMap>
<key1>value1</key1>
<key2>value2</key2>
</myMap>
</configuration>
...
Properties should be defined like the following:
...
/**
* My Properties.
*
* @parameter
*/
private Properties myProperties;
...
...
<configuration>
<myProperties>
<property>
<name>propertyName1</name>
<value>propertyValue1</value>
<property>
<property>
<name>propertyName2</name>
<value>propertyValue2</value>
<property>
</myProperties>
</configuration>
...
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 which tells Maven what setter and getter to use when the field is not accessed directly.
You can also configure a mojo using the executions tag. Using MyQueryMojo as an example, you may have something that will look like:
<project>
...
<build>
<plugins>
<plugin>
<artifactId>maven-myquery-plugin</artifactId>
<version>1.0</version>
<executions>
<execution>
<id>execution1</id>
<phase>test</phase>
<configuration>
<url>http://www.foo.com/query</url>
<timeout>10</timeout>
<options>
<option>one</option>
<option>two</option>
<option>three</option>
</options>
</configuration>
</execution>
<execution>
<id>execution2</id>
<configuration>
<url>http://www.bar.com/query</url>
<timeout>15</timeout>
<options>
<option>four</option>
<option>five</option>
<option>six</option>
</options>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
...
</project>
The first execution with id "execution1" binds this configuration to the test phase. Some goals can have default phases. The second execution does not have a phase tag, how do you think will the execution behave? If the goal is binded to a phase then it will execute to that phase. But if the goal is not binded to any lifecycle phases then it will be executed without executing any phases(as if it was executed in the CLI).
Note that execution id's don't have to be unique. Executions of the same id are merged.
How about if we have a multiple executions with different phases bound to it? How do you think will it behave? Let us use the example POM above again, but this time we shall bind execution2 to a phase.
<project>
...
<build>
<plugins>
<plugin>
...
<executions>
<execution>
<id>execution1</id>
<phase>test</phase>
...
</execution>
<execution>
<id>execution2</id>
<phase>install</phase>
<configuration>
<url>http://www.bar.com/query</url>
<timeout>15</timeout>
<options>
<option>four</option>
<option>five</option>
<option>six</option>
</options>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
...
</project>
If there are multiple executions bound to different phases, then the mojo is executed once for each phase indicated. Meaning, execution1 will be executed applying the configuration setup when the phase of the build is test, and execution2 will be executed applying the configuration setup when the build phase is already in install.
Now, Let us have another mojo example which is binded to a lifecycle phase.
@phase package
public class MyBindedQueryMojo
extends AbstractMojo
{
/**
* @parameter
*/
private String url;
/**
* @parameter
*/
private int timeout;
/**
* @parameter
*/
private String[] options;
public void execute()
throws MojoExecutionException
{
...
}
}
From the above mojo example, MyBindedQueryMojo is binded to package phase (see the "@phase" notation). But if we want to execute this mojo to install phase not with package we can rebind this mojo into a new lifecycle phase using the <phase> tag under <executions>.
<project>
...
<build>
<plugins>
<plugin>
<artifactId>maven-myquery-plugin</artifactId>
<version>1.0</version>
<executions>
<execution>
<id>execution1</id>
<phase>install</phase>
<configuration>
<url>http://www.bar.com/query</url>
<timeout>15</timeout>
<options>
<option>four</option>
<option>five</option>
<option>six</option>
</options>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
...
</project>
Now, MyBindedQueryMojo default phase which is package has been overrided by install phase.
Configurations inside the executions tag differ from those that are outside executions in that they cannot be used from a direct command line invocation. Instead they are only applied when the lifecycle phase they are bound to are invoked. Alternatively, if you move a configuration section outside of the executions section, it will apply globally to all invocations of the plugin.