There are many ways that we can use when we want to share our applications with other people. For example, we can create a binary distribution that can be downloaded from our website.

This blog post describes how we can create a runnable binary distribution by using the Maven Assembly Plugin.

The requirements of our binary distribution are:

  • The jar file that contains the classes of our example application must be copied to the root directory of the binary distribution.
  • The manifest of the created jar file must configure the classpath and the main class of our application.
  • The dependencies of our application must be copied to the lib directory.
  • The startup scripts of our application must be copied to the root directory of the binary distribution.

Let’s start by taking a quick look at our example application.

The Example Application

The example application of this blog post has only one class that writes the string ‘Hello World!’ to the log by using Log4j. The source code of the HelloWorldApp class looks as follows:

 1import org.apache.log4j.Logger;
 2
 3public class HelloWorldApp
 4{
 5    private static Logger LOGGER = Logger.getLogger(HelloWorldApp.class);
 6
 7    public static void main( String[] args )
 8    {
 9        LOGGER.info("Hello World!");
10    }
11}

The properties file that configures Log4j is called log4j.properties, and it is found from the src/main/resources directory. Our log4j.properties file looks as follows:

1log4j.rootLogger=DEBUG, R
2
3log4j.appender.R=org.apache.log4j.ConsoleAppender
4
5log4j.appender.R.layout=org.apache.log4j.PatternLayout
6log4j.appender.R.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%n

The startup scripts of our example application are found from the src/main/scripts directory. This directory contains the startup scripts for the Windows and *nix operating systems.

Let’s move on and find out how we can create a jar file that configures the classpath and the main class of our example application.

Creating the Jar File

We can package our application into a jar file by using the Maven Jar Plugin. We can configure the Maven Jar Plugin by following these steps:

  1. Ensure that classpath of our example application is added to the created manifest file.
  2. Specify that all dependencies of our application are found from the lib directory.
  3. Configure the main class of our example application.

The configuration of the Maven Jar Plugin looks as follows:

 1<plugin>
 2    <groupId>org.apache.maven.plugins</groupId>
 3    <artifactId>maven-jar-plugin</artifactId>
 4    <version>2.5</version>
 5    <configuration>
 6        <!-- Configures the created archive -->
 7        <archive>
 8            <!-- Configures the content of the created manifest -->
 9            <manifest>
10                <!-- Adds the classpath to the created manifest -->
11                <addClasspath>true</addClasspath>
12                <!--
13                    Specifies that all dependencies of our application are found
14                    from the lib directory.
15                -->
16                <classpathPrefix>lib/</classpathPrefix>
17                <!-- Configures the main class of the application -->
18                <mainClass>net.petrikainulainen.mavenassemblyplugin.HelloWorldApp</mainClass>
19            </manifest>
20        </archive>
21    </configuration>
22</plugin>

Let’s move on and find out how we can assemble the binary distribution of our example application.

Assembling the Binary Distribution

We can assemble our binary distribution by using the Maven Assembly Plugin. If we want to create a binary distribution that fulfills our requirements, we have to follow these steps:

  1. Create an assembly descriptor that dictates the execution of the Maven Assembly Plugin.
  2. Configure the Maven Assembly Plugin to use the created assembly descriptor.

First, we have create an assembly descriptor that dictates the execution of the Maven Assembly Plugin. We can create this assembly descriptor by following these steps:

  1. Create an assembly.xml file to the src/assembly directory.
  2. Configure the format of our binary distribution. Ensure that a zip file is created.
  3. Copy the dependencies of our application to the lib directory.
  4. Copy the startup scripts of our application from the src/main/scripts directory to the root directory of the binary distribution.
  5. Copy the jar file of our example application from the target directory to the root directory of the binary distribution.

Our assembly descriptor looks as follows:

 1<assembly>
 2    <id>bin</id>
 3    <!-- Specifies that our binary distribution is a zip package -->
 4    <formats>
 5        <format>zip</format>
 6    </formats>
 7
 8    <!-- Adds the dependencies of our application to the lib directory -->
 9    <dependencySets>
10        <dependencySet>
11            <!--
12                Project artifact is not copied under library directory since
13                it is added to the root directory of the zip package.
14            -->
15            <useProjectArtifact>false</useProjectArtifact>
16            <outputDirectory>lib</outputDirectory>
17            <unpack>false</unpack>
18        </dependencySet>
19    </dependencySets>
20
21    <fileSets>
22        <!--
23            Adds startup scripts to the root directory of zip package. The startup
24            scripts are copied from the src/main/scripts directory.
25        -->
26        <fileSet>
27            <directory>${project.build.scriptSourceDirectory}</directory>
28            <outputDirectory></outputDirectory>
29            <includes>
30                <include>startup.*</include>
31            </includes>
32        </fileSet>
33        <!--
34            Adds the jar file of our example application to the root directory
35            of the created zip package.
36        -->
37        <fileSet>
38            <directory>${project.build.directory}</directory>
39            <outputDirectory></outputDirectory>
40            <includes>
41                <include>*.jar</include>
42            </includes>
43        </fileSet>
44    </fileSets>
45</assembly>

Second, we have to configure the Maven Assembly Plugin to use the assembly descriptor that we created in step one. We can do this by adding the following plugin declaration to the plugins section of our POM file:

 1<plugin>
 2    <groupId>org.apache.maven.plugins</groupId>
 3    <artifactId>maven-assembly-plugin</artifactId>
 4    <version>2.5.1</version>
 5    <configuration>
 6        <!-- Configures the used assembly descriptor -->
 7        <descriptors>
 8            <descriptor>src/main/assembly/assembly.xml</descriptor>
 9        </descriptors>
10    </configuration>
11</plugin>

We have now configured the Maven Assembly Plugin to create our binary distribution. Let’s move on and find out what this really means.

What Did We Just Do?

We can create our binary distribution by running the command mvn clean package assembly:single at the command prompt. After we have done this, Maven creates the maven-assembly-plugin-bin.zip file to the target directory. This zip package is the binary distribution of our example application.

The name of the binary distribution is created by using the following formula: [the value of the finalName element]-[the id of the used assembly].[the format of the distribution].

In other words, the name of the created binary distribution is maven-assembly-plugin-bin.zip because:

  1. The value of the finalName element, which is found from our pom.xml file, is maven-assembly-plugin.
  2. The id of our assembly is bin.
  3. We want to create a binary distribution that is packaged into a zip file.

When we run the command unzip maven-assembly-plugin-bin.zip at the command prompt, the maven-assembly-plugin-bin directory is created to the target directory. The content of the created directory is described in the following:

  • The maven-assembly-plugin-bin directory contains the jar file of our example application and the startup scripts.
  • The maven-assembly-plugin-bin/lib directory contains the log4j-1.2.16.jar file.

We can run our example application application by using the startup scripts found from the maven-assembly-plugin-bin directory. When we run our application, we see the following output:

1$ ./startup.sh
20    [main] INFO  net.petrikainulainen.mavenassemblyplugin.HelloWorldApp  - Hello World!

Let’s move on and summarize what we learned from this blog post.

Summary

This blog has taught us two things:

  • We can customize the manifest of the created jar file by using the Maven Jar Plugin.
  • We can create a binary distribution, which doesn’t use the so called “fat jar” approach, by using the Maven Assembly plugin.