With the advancement of containerization and microservices, the idea of distributing all dependencies in s separate library folder is fading away. Instead, developers prefer to create a fat JAR using Maven so that they don’t have to worry about missing a dependency. Note that sometimes the fat JAR is also referred to as Uber JAR or JAR with dependencies. This article introduces you Apache Maven Shade plugin to create a fat JAR using Maven.

Requirements


Create a New Maven Project

Step 1:
Create a new Maven project in IntelliJ Idea with the group id: com.javahelps.maven and artifact id: maven-fat-jar.

Step 2:
Add the following dependency to the pom.xml file. Here we are adding only the logback dependency as an example to demonstrate building a fat JAR using Maven. The log back has no connection with creating an uber Jar.

<?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>com.javahelps.maven</groupId>
<artifactId>maven-fat-jar</artifactId>
<version>1.0-SNAPSHOT</version>

<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<logback.version>1.4.5</logback.version>
</properties>

<dependencies>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>${logback.version}</version>
</dependency>

<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>${logback.version}</version>
</dependency>
</dependencies>

</project>

Step 3:
Modify the Main class as shown below to use the logger to log a hello world message.

package com.javahelps.maven;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Main {

private static final Logger logger = LoggerFactory.getLogger(Main.class);

public static void main(String[] args) {
logger.info("Hello world!");
}
}

Step 4:
Run the following command to build the package.

mvn clean package

After packaging the project using the above command, you will get the maven-fat-jar-1.0-SNAPSHOT.jar in the target folder. Don’t be deceived by the name “fat-jar“. The JAR file name is from the artifact name defined in Step 1.

Step 5:
Run the following command to see the files included in the maven-fat-jar-1.0-SNAPSHOT.jar file. You will see only the Main class included in the JAR file.

jar -tf target/maven-fat-jar-1.0-SNAPSHOT.jar

Step 6:
Enter the following command to run the Main class from the JAR file.

java -cp target/maven-fat-jar-1.0-SNAPSHOT.jar com.javahelps.maven.Main

You will be welcomed by “java.lang.NoClassDefFoundError: org/slf4j/LoggerFactory” saying the log back dependency is not in the classpath. To solve this problem, you must find the logback dependency from the local Maven repository and include it in the classpath. This is where creating an uber jar helps.


Let’s Create a Fat JAR Using Maven

Step 1:
To create an uber jar, add the following plugin to the pom.xml file. The plain plugin configuration is given below but you must put it inside the build.plugins tag as shown in the final pom.xml down below.

Note that the reference for the Main class is added to the plugin so that you can run the built fat jar without specifying the class name explicitly. This is another advantage the Shade plugin provides.

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.4.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.javahelps.maven.Main</mainClass>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>

After making all the changes, the final pom.xml should look like this:

<?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>com.javahelps.maven</groupId>
<artifactId>maven-fat-jar</artifactId>
<version>1.0-SNAPSHOT</version>

<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<logback.version>1.4.5</logback.version>
</properties>

<dependencies>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>${logback.version}</version>
</dependency>

<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>${logback.version}</version>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.4.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.javahelps.maven.Main</mainClass>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>


Step 2:
Build the project once again using Apache Maven.

mvn clean package

Step 3:
This time in the target folder, there must be two jar files:

  • original-maven-fat-jar-1.0-SNAPSHOT.jar – The original JAR file
  • maven-fat-jar-1.0-SNAPSHOT.jar – The fat JAR with dependencies included in it. You can notice the fat JAR is slightly bigger than the original JAR in size due to the extra dependencies.

Step 4:
Run the following command to see the files included in the maven-fat-jar-1.0-SNAPSHOT.jar file. You will see your Main class and all the classes from the logback library.

jar -tf target/maven-fat-jar-1.0-SNAPSHOT.jar

Step 5:
You can run the fat jar using the “java -jar” command because the Maven Shade plugin adds the Main class into the META-INF/MANIFEST.MF file.

java -jar target/maven-fat-jar-1.0-SNAPSHOT.jar

This time you must get the Hello World! info log printed in the terminal. Apache Maven Shade plugin provides advanced features like selecting what to include in the uber jar and the option to rename certain packages in case you have any conflicts. For more details, visit the Apache Maven Shade plugin’s official website.

You can download the project from GitHub.

Have you found this article useful? Please let me know below in the comments. Knowing someone found my articles useful motivates me to write more. Also, comment below if you face any issues with following this article or getting it working. I will try my best to help you resolve the problem. The Java Helps community is also willing to help each other and grow together.

Share.
Exit mobile version