How can I create an executable JAR with all dependencies included using Maven for easy distribution of my Java application?
To create an executable JAR with all dependencies included using Maven, you can use either the Maven Assembly Plugin, Maven Shade Plugin, or Maven Exec JAR Plugin. The most common approach is using the Maven Shade Plugin, which creates a “fat JAR” by packaging all dependencies into a single executable JAR file, allowing you to run your application with a simple java -jar your-app.jar command.
Contents
- Using Maven Shade Plugin
- Using Maven Assembly Plugin
- Using Maven Exec JAR Plugin
- Configuring the Main Class
- Common Issues and Solutions
- Best Practices
- Building and Running Your JAR
Using Maven Shade Plugin
The Maven Shade Plugin is the most popular choice for creating executable JARs with all dependencies included. It packages all dependencies into a single JAR file and can also create an executable manifest.
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.5.1</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>com.example.YourMainClass</mainClass>
</transformer>
</transformers>
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
</filters>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
The Shade Plugin offers additional features like merging service files and handling duplicate classes through the <filters> section.
Using Maven Assembly Plugin
The Maven Assembly Plugin is another option that creates distribution packages including your JAR and all dependencies in a directory structure.
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.7.1</version>
<configuration>
<archive>
<manifest>
<mainClass>com.example.YourMainClass</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
The Assembly Plugin creates a JAR with “-with-dependencies” suffix, which includes all dependencies in the same structure as they appear in your project.
Using Maven Exec JAR Plugin
The Maven Exec JAR Plugin is simpler and focuses specifically on creating executable JARs with proper classpath configuration.
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.3.0</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<classpathPrefix>lib/</classpathPrefix>
<mainClass>com.example.YourMainClass</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>3.6.1</version>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>prepare-package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/lib</outputDirectory>
<overWriteReleases>false</overWriteReleases>
<overWriteSnapshots>false</overWriteSnapshots>
<overWriteIfNewer>true</overWriteIfNewer>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
This approach creates a separate lib directory for dependencies rather than packaging them inside the JAR, which can be useful for debugging and dependency management.
Configuring the Main Class
Regardless of which plugin you choose, you need to specify the main class that should be executed when the JAR is run. This is configured in the manifest:
<manifest>
<mainClass>com.example.YourMainClass</mainClass>
</manifest>
Alternatively, you can specify the main class in your pom.xml properties:
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<mainClass>com.example.YourMainClass</mainClass>
</properties>
Important: Make sure the main class you specify actually exists in your project and has a
public static void main(String[] args)method.
Common Issues and Solutions
Duplicate Classes
When using the Shade Plugin, you might encounter duplicate class conflicts. You can handle this with:
<configuration>
<filters>
<filter>
<artifact>com.example:conflicting-library</artifact>
<includes>
<include>com/example/RequiredClass.class</include>
</includes>
</filter>
</filters>
</configuration>
Security Files Exclusion
The Shade Plugin might fail due to signature files. Exclude them:
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
</filters>
Manifest Configuration Issues
Ensure your manifest is properly configured with the main class. You can verify the manifest content using:
jar tf your-app.jar | grep META-INF/MANIFEST.MF
Best Practices
-
Use the Shade Plugin for true fat JARs - It’s the most reliable way to create a single executable JAR with all dependencies.
-
Exclude unnecessary files - Remove signature files and META-INF entries to reduce JAR size and avoid conflicts.
-
Use appropriate Java version - Ensure your Maven configuration matches the Java version you’re using for development.
-
Test your JAR - Always test the generated JAR on the target deployment environment before distribution.
-
Consider native images - For performance-critical applications, consider using GraalVM to create native executables instead of JARs.
-
Use dependency management - Properly manage your dependencies in the
dependencyManagementsection of yourpom.xmlto avoid version conflicts.
Building and Running Your JAR
Building the JAR
Once configured, build your executable JAR using Maven:
mvn clean package
The generated JAR will typically be in the target/ directory with a name like your-app-1.0.0.jar or your-app-1.0.0-jar-with-dependencies.jar.
Running the JAR
Run your executable JAR with:
java -jar target/your-app-1.0.0-jar-with-dependencies.jar
Verifying Dependencies
You can inspect the contents of your JAR to verify dependencies are included:
jar tf target/your-app-1.0.0-jar-with-dependencies.jar | head -20
For more detailed inspection:
jar -tf target/your-app-1.0.0-jar-with-dependencies.jar | grep com/example
Conclusion
Creating an executable JAR with all dependencies included using Maven is straightforward with the right plugin configuration. The Maven Shade Plugin is generally the best choice for creating true fat JARs, while the Assembly Plugin offers more flexibility in packaging options, and the Exec JAR Plugin provides a simpler approach with separate dependency directories.
Key recommendations:
- Use the Maven Shade Plugin for most applications requiring a single executable file
- Always configure the main class properly in your manifest
- Test your JAR thoroughly before distribution
- Consider the trade-offs between different approaches based on your deployment needs
By following these practices, you can easily distribute your Java applications as self-contained executable JAR files that run on any system with Java installed.