What Is a Fat Jar

What is a fat JAR?

The fat jar is the jar, which contains classes from all the libraries, on which your project depends and, of course, the classes of current project.

In different build systems fat jar is created differently, for example, in Gradle one would create it with (instruction):

task fatJar(type: Jar) {
manifest {
attributes 'Main-Class': 'com.example.Main'
}
baseName = project.name + '-all'
from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } }
with jar
}

In Maven it's being done this way (after setting up regular jar):

<pluginRepositories>
<pluginRepository>
<id>onejar-maven-plugin.googlecode.com</id>
<url>http://onejar-maven-plugin.googlecode.com/svn/mavenrepo</url>
</pluginRepository>


<plugin>
<groupid>org.dstovall</groupid>
<artifactid>onejar-maven-plugin</artifactid>
<version>1.4.4</version>
<executions>
<execution>
<configuration>
<onejarversion>0.97</onejarversion>
<classifier>onejar</classifier>
</configuration>
<goals>
<goal>one-jar</goal>
</goals>
</execution>
</executions>
</plugin>

How to create a fat jar?

What you need here is an executable jar that will not only contain your classes, but also classes from all your dependencies.
For that you can use the Maven Assembly Plugin.

See the sample code below.

<project>
[...]
<build>
[...]
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.0.0</version>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<archive>
<manifest>
<mainClass>org.sample.App</mainClass> // specify your main class here
</manifest>
</archive>
</configuration>
<executions>
<execution>
<id>make-assembly</id> <!-- this is used for inheritance merges -->
<phase>package</phase> <!-- bind to the packaging phase -->
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
[...]
</project>

Then, run mvn package and the executable jar should be located in the folder target (with a name like ProjectName-1.0-SNAPSHOT-jar-with-dependencies.jar).

What is an uber jar?

Über is the German word for above or over (it's actually cognate with the English over).

Hence, in this context, an uber-jar is an "over-jar", one level up from a simple JAR (a), defined as one that contains both your package and all its dependencies in one single JAR file. The name can be thought to come from the same stable as ultrageek, superman, hyperspace, and metadata, which all have similar meanings of "beyond the normal".

The advantage is that you can distribute your uber-jar and not care at all whether or not dependencies are installed at the destination, as your uber-jar actually has no dependencies.

All the dependencies of your own stuff within the uber-jar are also within that uber-jar. As are all dependencies of those dependencies. And so on.


(a) I probably shouldn't have to explain what a JAR is to a Java developer but I'll include it for completeness. It's a Java archive, basically a single file that typically contains a number of Java class files along with associated metadata and resources.

Spring Boot Thinner Fat Jar - Split jar in 2 (app / libs)

I managed to do what I wanted.

For that purpose, I had to extend the bootJar task in gradle into 2 tasks, one for the dependencies, and one for my libraries...

task bootJarDeps(type: org.springframework.boot.gradle.tasks.bundling.BootJar) {
description "Generates JAR with just dependencies."
exclude 'com.mypackage.**.jar'
archiveName 'deps.jar'

mainClass = 'com.mypackage.App'
with bootJar
}

The mainClass in the dependencies is useless, but still required for the task.

task bootJarApp(type: org.springframework.boot.gradle.tasks.bundling.BootJar) {
description "Generates JAR without dependencies."
include 'com.mypackage.**.jar'
mainClass = 'com.mypackage.App'
archiveName 'app.jar'
with bootJar
}

Maven: Fat jar as local dependency

Fat JARs as dependencies are dangerous because if a fat jar contains the contents of x.jar and x.jar is also present on the classpath, then you usually get a conflict. Maven will not resolve the conflict because Maven has no knowledge which JARs are included in your fat JAR.

So when you have a fat JAR dependency you need to make sure that everything inside the fat JAR is not a dependency elsewhere in the project, and if so, you should exclude it.

If you shade the content, you might get away without such conflicts.

Why is there no easy way to create a fat Jar with Gradle?

I am assuming the JAR in question is private by your usage of client.


There is a plugin from the community that is often recommended: https://imperceptiblethoughts.com/shadow/

Gradle also offers a plugin to create a fat/uber JAR, but is more geared towards applications hence the name: Application plugin. -- more on this later

If you intend for the API client JAR you are creating to be used in other clients' build tools such as Maven or Gradle, then you should not create a fat JAR and instead document that in order for clients to include your API client JAR, they will need to provide X, Y, Z dependencies as part of their build process. You will also need to communicate the minimum or maximum supported version your support. This gives the client the flexibility to provide X, Y, Z dependencies from wherever they want. This is where the jar task provided by Java plugin comes into play.

But if you do not want clients to override the version of internal dependencies your client uses, then yes, you will need to build a fat JAR that includes those dependencies which is where the Shadow plugin (linked above) comes into play.

Now back to the Application plugin, underneath, it applies the Distribution plugin which provides the capability to create a fat JAR. However, this is not commonly used for reasons I do not know and instead you will find the aforementioned Shadow plugin used more commonly. This is probably because the Shadow plugin offers more control on how the dependencies are packaged in the fat JAR such as relocating packages.



Related Topics



Leave a reply



Submit