Packaging Dependencies into a Single JAR with Maven

Introduction

When developing Java applications using Maven, it’s common to rely on external libraries (dependencies). These dependencies are typically managed and downloaded by Maven. However, when you need to distribute your application, you might want to package all the necessary dependencies into a single, self-contained JAR file. This simplifies deployment and ensures that the application has everything it needs to run without relying on external libraries being present on the target system. This tutorial explains how to achieve this using the Maven Assembly Plugin and alternative methods.

Understanding the Problem

By default, Maven builds your application and lists its dependencies in the pom.xml file. However, the resulting JAR file only contains your application’s code, not the code from the dependencies. To run the application, you need to ensure that all dependencies are available on the classpath at runtime. Packaging everything into one JAR solves this problem.

Using the Maven Assembly Plugin

The most common and recommended approach is to use the Maven Assembly Plugin. This plugin provides a flexible way to assemble project artifacts into different formats, including a "jar-with-dependencies" format.

Step 1: Add the Assembly Plugin to your pom.xml

Add the following configuration within the <build> section of your pom.xml file:

<build>
    <plugins>
        <plugin>
            <artifactId>maven-assembly-plugin</artifactId>
            <executions>
                <execution>
                    <id>create-my-bundle</id>
                    <phase>package</phase>
                    <goals>
                        <goal>single</goal>
                    </goals>
                    <configuration>
                        <descriptorRefs>
                            <descriptorRef>jar-with-dependencies</descriptorRef>
                        </descriptorRefs>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

Explanation:

  • <artifactId>maven-assembly-plugin</artifactId>: This specifies the Assembly Plugin.
  • <executions>: Defines when the plugin should be executed.
  • <execution>: Defines a single execution of the plugin.
  • <id>: A unique identifier for this execution.
  • <phase>package</phase>: Specifies that the plugin should be executed during the package phase of the Maven build lifecycle (after compilation and testing).
  • <goals><goal>single</goal></goals>: This tells the plugin to create a single assembled artifact.
  • <configuration>: Contains configuration options for the plugin.
  • <descriptorRefs><descriptorRef>jar-with-dependencies</descriptorRef></descriptorRefs>: This tells the plugin to use the pre-defined jar-with-dependencies descriptor, which creates a JAR file containing your application code and all of its dependencies.

Step 2: Build Your Project

Run the following command in your project directory:

mvn package

This will trigger the Maven build process, and the Assembly Plugin will execute during the package phase, creating a JAR file with all dependencies bundled inside. The resulting JAR file will be located in the target directory.

Making the JAR Executable (Optional)

If you want to create an executable JAR, you need to specify the main class to run. Add the following inside the <configuration> element of the maven-assembly-plugin:

<archive>
    <manifest>
        <mainClass>fully.qualified.MainClass</mainClass>
    </manifest>
</archive>

Replace fully.qualified.MainClass with the fully qualified name of the class containing your main method.

Alternative Methods

While the Assembly Plugin is the most recommended, here are a couple of other approaches:

1. Copy Dependencies and Update Manifest:

This involves manually copying the dependency JARs into a lib directory within your project and updating the JAR manifest to include them on the classpath. This is generally more complex and less maintainable than using the Assembly Plugin.

2. Maven Shade Plugin:

The Maven Shade Plugin is another option. It can package and rename dependencies to avoid classpath conflicts. This can be particularly useful when dealing with dependencies that have conflicting resources or class names.

Best Practices

  • Consider the Size: Bundling all dependencies can result in a large JAR file. If size is a critical concern, explore options for excluding unnecessary dependencies or using a more granular approach to packaging.
  • Dependencies Licensing: Be mindful of the licensing terms of your dependencies. Ensure that you are complying with all applicable licenses when distributing your application.
  • Use a Version Control System: Always use a version control system (like Git) to manage your project and track changes to your pom.xml file.

Leave a Reply

Your email address will not be published. Required fields are marked *