November 29, 2012

Maven dependency unpacking filtering in custom assemblies

Introduction

I have been using Maven assemblies for a while to do some relatively simple building of artifacts which Maven does not build out of the box.  Assemblies are quite powerful and can do a lot for you. I ran into a problem with dependency unpacking. I needed some of the unpacked files to be filtered so as to replace ${variablename} inside the files but found this feature not supported.  The purpose of this article is to demonstrate how dependency unpacking filtering can be done when using custom Maven assemblies.

Of course remember that the plugins attached to a particular <phase> are executed by Maven in the order you have them in our pom - put the plugins in the wrong order and you won't get the right results.

1. Use maven-dependency-plugin to get the dependency unpacked.

First  you want to use the maven-dependency-plugin to unpack your dependency. Unpack inside the /target directory for use later.  The XML below shows configuration to do this.

1:  <plugin>  
2:    <groupId>org.apache.maven.plugins</groupId>  
3:    <artifactId>maven-dependency-plugin</artifactId>  
4:    <version>2.6</version>  
5:    <executions>  
6:     <execution>  
7:      <id>unpack-dependencies</id>  
8:      <phase>prepare-package</phase>  
9:      <goals>  
10:       <goal>unpack-dependencies</goal>  
11:      </goals>  
12:      <configuration>     
13:       <includeArtifactIds>SomeArtifactId</includeArtifactIds>         
14:       <outputDirectory>${project.build.directory}/SomeArtifactId</outputDirectory>             
15:      </configuration>  
16:     </execution>  
17:    </executions>  
18:   </plugin>  


In the code above:

Line #8 links this plugin configuration to the prepare-package phase, which is typically what you will want to do since you need to unpack your dependencies before the package phase runs your custom assembly

Line #10 sets the goal to unpack-dependencies, which of course means the dependency will be unzipped.

Line #13 is the <includeArtifactIds> tag which can take a comma-separated list of <dependency><artifactId> id values. I typically like to use only 1 value though and if I need to unpack multiple dependencies I create multiple plugin configurations.

Line #14 is the <outputDirectory> tag and this specifies where the dependency is unzipped.  Typically, just dump it into some /target subdirectory.

2. Use maven-assembly-plugin to build your assembly.

Next you will need to configure the maven-assembly-plugin to execute during your build. Of course put this plugin configuration AFTER the maven-dependency-plugin configuration so Maven executes them in the right order. The XML below shows configuration to do this:

1:        <plugin>  
2:          <artifactId>maven-assembly-plugin</artifactId>  
3:          <executions>  
4:            <execution>  
5:              <configuration>  
6:                <descriptors>  
7:                  <descriptor>my_assembly.xml</descriptor>  
8:                </descriptors>  
9:              </configuration>            
10:              <id>create_directory</id>  
11:              <phase>prepare-package</phase>  
12:              <goals>  
13:                <goal>single</goal>  
14:              </goals>  
15:            </execution>  
16:          </executions>  
17:        </plugin>  


In code above:

Line #7 says to use the assembly defined in your my_assembly.xml file.

Line #11 links this plugin configuration to the prepare-package phase.  This is the same phase the maven-dependency-plugin configured above is linked to. Maven will run this maven-assembly-plugin configuration after the maven-dependency-plugin configuration as long as have them in that order in the pom.

The my_assembly.xml file is the configuration for your custom assembly.  To work with the unpacked dependency files, you refer to them just like you would any other file.  The XML below shows configuration to do this.

1:  <fileSet>  
2:        <directory>${project.build.directory}/SomeArtifactId</directory>  
3:        <outputDirectory>/where/to/put/it/in/your/assembly</outputDirectory>  
4:        <includes>  
5:          <include>file-to-be-filtered.txt</include>          
6:        </includes>  
7:        <filtered>true</filtered>  
8:  </fileSet>  


As you can see, you can use the <filtered> option to make sure the files are filtered. Of course, use multiple configurations if you need to filter some files but not others.

In the code above:

Line #2 says to use the files which were unpacked by the maven-dependency-plugin

Line #3 says where to put the files in your assembly

Line #5 says what files are to be included.

Line #7 says to filter the files.  This will of course replace the ${variablename} strings

Summary

That's it, enjoy