Maven Tips and Tricks

Maven Tips and TricksErik EnglundBlockedUnblockFollowFollowingMay 30Image by Gerd Altmann from PixabayI’ve been writing Maven pom’s for over 10 years.

Over that time I’ve learned many tricks to get maven to work the way I want and present my developers with a great experience.

Maven WrapperMaven wrapper is a lot like the Gradle Wrapper.

The wrapper provides an executable shell script then will download Maven if it needs it and then use that to complete the build.

This allows you to configure your maven version in your code.

This is invaluable on large teams where not everyone always has the same version of Maven installed on their systems.

To add maven wrapper to your project run themvn -N io.

takari:maven:0.

7.

6:wrapperFurther ReadingMaven WrapperExecution Block’s ConfigurationWhen you add a plugin to your build you can sometimes rely on its default configuration but more often than not you will want to configure it for your specific project needs.

This means providing a configuration block and possibly an execution block.

The execution block is a great way to isolate a configuration to a specific circumstance.

Think of it like this.

The root configuration block is for global configuration.

The inner execution configuration block is for locally scoped configuration.

For example:<plugin> <groupId>org.

example</groupId> <artifactId>example-plugin</artifactId> <version>1.

0.

0</version> <configuration> <globalValue>someValue</globalValue> </configuration> <executions> <execution> <id>doSomething</id> <phase>generate-sources</phase> <goals> <goal>runIt</goal> </goals> <configuration> <localValue>otherValue</localValue> <globalValue>override</globalValue> </configuration> </execution> <execution> <id>doSomethingElse</id> <phase>generate-sources</phase> <goals> <goal>runIt</goal> </goals> <configuration> <localValue>otherValue2</localValue> </configuration> </execution> </executions></plugin>Here we have two executions of the same plugin.

A global value for the property globalValue is assigned as someValue.

The first execution doSomething assigns a localValue property to otherValue and overrides the globalValue with a value of override.

The second execution doSomethingElse also assigned a localValue property to otherValue2 and then inherits the globalValue.

Executing Execution BlocksWith execution blocks you can also execute individual steps.

For instance, if I wanted to run ONLY the second execution block from the example above I would run:mvn org.

example:example-plugin@doSomethingElseNow this can be somewhat tedious for developers to have to lookup an execution id that you choose.

Especially if this execution exists in some other parent pom.

Thankfully, there is a work around for this.

If you have an execution that you want to easily expose to your developers then set the execution id to default-cli.

This is a special ID that maven will look for when someone executes a plugin without an execution ID.

For example:mvn org.

example:example-pluginHere the ID of default-cli is implied.

Now in general execution ID’s are not required.

But they are incredibly useful and I recommend you always provide one.

Plugin ManagementYou can also use the plugin management section as a way of configuring a plugin without executing it.

Now you can also do this with profiles but using the pluginManagement section ensure a global shared configuration.

For instance, I could put the previous plugin configuration into the pluginManagement section like so:<pluginManagement> <plugins> <plugin> <groupId>org.

example</groupId> <artifactId>example-plugin</artifactId> <version>1.

0.

0</version> <executions> <execution> <id>doSomething</id> <phase>generate-sources</phase> <goals> <goal>runIt</goal> </goals> <configuration> <localValue>otherValue</localValue> <globalValue>override</globalValue> </configuration> </execution> .

</executions> </plugin> </plugins></pluginManagement>Now even though the phase of our plugin is set to generate-sources if I run:mvn generate-sourcesOur plugin will NOT run.

This is because by placing our plugin configuration in the pluginManagement section we are giving maven a template for execution, but not telling it to execute it.

Why would you want to do this?Its a good way to share a configuration across all execution types.

I find this specifically useful for configuring static code analysis tools like check-style where I want a shared configuration across all executions, command line and part of the build.

None PhaseLets say you have a plugin that has a default execution phase but you don’t want it to run.

You could override the default phase with your own phase but then its still going to run.

What if you don’t want it to run at all?Well then set the phase to none.

None phase, never heard of it.

Well guess what, neither has maven!.So it won’t execute your plugin.

This is not an error, maven just won’t execute since there is no none phase.

This is a great trick to disable an execution of a plugin.

For example, lets assume the previous configuration was in a parent pom.

I could disable the execution of doSomething like so:<plugin> <groupId>org.

example</groupId> <artifactId>example-plugin</artifactId> <executions> <execution> <id>doSomething</id> <phase>none</phase> </execution> </executions></plugin>Plugin Configuration InheritanceSpeaking of parent pom’s, there are cases where I want to change or add to the plugin configuration of a parent.

This is easy if I am changing the value of a single element.

For example, here I am adding a configuration element to the parent execution of doSomething:<plugin> <groupId>org.

example</groupId> <artifactId>example-plugin</artifactId> <executions> <execution> <id>doSomething</id> <configuration> <newValue>otherValue</newValue> </configuration> </execution> </executions></plugin>Here the parent configuration remains unchanged.

I can follow the same strategy if I want to override a parent configuration.

<plugin> <groupId>org.

example</groupId> <artifactId>example-plugin</artifactId> <executions> <execution> <id>doSomething</id> <configuration> <localValue>childValue</localValue> </configuration> </execution> </executions></plugin>Here I’ve overridden the parent value of localValue with childValue.

Note: You can only override elements within the same scopingThis means I can’t provide a global configuration element for localValue in a child pom and expect it to override the value in all parent execution configurations.

If I wanted to override the value in all the parent execution configurations I would need to list each parent execution in my child pom and provide a configuration in each of those.

Plugin Configuration Inheritance: Lists and MapsSometimes the configuration provides list or map elements.

The default behavior by maven will be to try and merge these definitions.

Let say your parent has the following configuration with a list and map element:<plugin> <groupId>org.

example</groupId> <artifactId>example-plugin</artifactId> <version>1.

0.

0</version> <configuration> <globalValue>someValue</globalValue> </configuration> <executions> <execution> <id>doSomething</id> <phase>generate-sources</phase> <goals> <goal>runIt</goal> </goals> <configuration> <listValues> <value>hello</value> </listValues> <mapValues> <key1>value1</key1> <key2>value2</key2> </mapValues> </configuration> </execution> </executions></plugin>How do I go about adding elements to the list?Add the following attribute to the list element:combine.

children=”append”How do I go about overriding the map?Add the following attribute to the map element:combine.

self="override"For example the configuration:<plugin> <groupId>org.

example</groupId> <artifactId>example-plugin</artifactId> <version>1.

0.

0</version> <configuration> <globalValue>someValue</globalValue> </configuration> <executions> <execution> <id>doSomething</id> <phase>generate-sources</phase> <goals> <goal>runIt</goal> </goals> <configuration> <listValues combine.

children="append"> <value>world</value> </listValues> <mapValues combine.

self="override"> <key3>value1</key3> </mapValues> </configuration> </execution> </executions></plugin>will result in an effect pom of:<plugin> <groupId>org.

example</groupId> <artifactId>example-plugin</artifactId> <version>1.

0.

0</version> <configuration> <globalValue>someValue</globalValue> </configuration> <executions> <execution> <id>doSomething</id> <phase>generate-sources</phase> <goals> <goal>runIt</goal> </goals> <configuration> <listValues combine.

children="append"> <value>hello</value> <value>world</value> </listValues> <mapValues combine.

self="override"> <key3>value1</key3> </mapValues> </configuration> </execution> </executions></plugin>Further ReadingMaven DocumentationMaven BOMWhen you build a library that has multiple different modules you will often desire that all the same versions of your modules get consumed together.

You could rely on the consumer to do this or you could help them along by creating a BOM.

Traditionally, if you wanted to define a version for a particular dependency or set of dependencies you would setup a dependencyManagement block in you parent pom.

However, parent pom’s use an inheritance model and quickly run into problems when you want to consume different libraries.

A maven Bill of Materials or BOM, is a special packaging that allows you to compose dependencyManagement blocks.

To create a BOM simply create a maven module of packaging pom and setup your dependencyManagement block like normal:<?xml version="1.

0" encoding="UTF-8"?><project xmlns="http://maven.

apache.

org/POM/4.

0.

0" xmlns:xsi="http://www.

w3.

org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.

apache.

org/POM/4.

0.

0 http://maven.

apache.

org/xsd/maven-4.

0.

0.

xsd"> <modelVersion>4.

0.

0</modelVersion> <groupId>io.

github.

efenglu.

examples</groupId> <artifactId>examples-bom</artifactId> <version>1.

0.

0</version> <packaging>pom</packaging> <properties> <examples.

version>${project.

version}</examples.

version> </properties> <dependencyManagement> <dependencies> <dependency> <groupId>io.

github.

efenglu.

examples</groupId> <artifactId>example-1</artifactId> <version>${examples.

version}</version> </dependency> <dependency> <groupId>io.

github.

efenglu.

examples</groupId> <artifactId>example-2</artifactId> <version>${examples.

version}</version> </dependency>.

</dependencies> </dependencyManagement></project>Then to consume the BOM add the following to your own dependencyManagement block:<dependencyManagement> <dependencies> <dependency> <groupId>io.

github.

efenglu.

examples</groupId> <artifactId>examples-bom</artifactId> <version>1.

0.

0</version> <type>pom</type> <scope>import</scope> </dependency>.

</dependencies></dependencyManagement>Notice the type is pom and the scope is import.

This will cause all the dependencies within the dependencyManagement block of the BOM to be imported into your dependencyManagement block.

Further ReadingMaven BOMSetting VersionSetting the version of a single pom is trivial.

Simply change the value in the version element.

However, on large projects with parents and multiple modules changing the version can be tedious and error prone when done manually.

Thankfully, maven has a tool to make changing the version dirt simple, even in large projects.

Run the following command:mvn versions:setMaven will then prompt for the version you want to change the project to.

If this is a parent pom all child poms will have their versions updated accordingly.

Further ReadingMaven Versions PluginEffective POMHow can I get a better picture of what maven is going to do or why it’s going to do something?The best way is to generate the effective pom.

The effective pom is a complete look at how maven see’s your pom file after it has replaced all properties, inherited all configurations.

and merged or appended configurations as necessary.

This is incredibly helpful when debugging plugin configurations and should be your first go-to for maven configuration problems.

To generate the effective pom simply run:mvn help:effective-pomFurther reading:Maven Help Plugin.

. More details

Leave a Reply