What is a fat JAR? [duplicate]
Asked Answered
K

6

196

I've heard people say that they create a fat JAR and deploy it. What do they actually mean ?

Kittykitwe answered 3/10, 2013 at 4:31 Comment(5)
when you want to ship your product as jar you normally want to put classes in all dependent jars into one single big jar file.Wakerly
@Nadeem_MK meta.stackexchange.com/questions/5280/embrace-the-non-googlers meta.stackexchange.com/questions/8724/…Sawfish
The original answer was pointing to this link: javacodegeeks.com/2012/11/…Luggage
I wonder if a fat jar is the java equivalent of static linking in cMassasauga
@SridharSarnobat Not quite. The "thin jar" is the equivalent of a statically linked C or C++ app. A "fat jar" includes the runtime but for a statically linked app, that of course is the underlying OS incl. syslibs.Reddick
U
117

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>
  </pluginRepositories>
<!-- ... -->

<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>
Unnumbered answered 28/4, 2015 at 16:53 Comment(6)
So is "fat jar" just another name for "uber jar"?Kabyle
@Kabyle Yes, exactly.Unnumbered
Why use some third party plugin when there is maven assembly plugin with it's jar-with-dependencies assembly?Merwyn
@Merwyn you can add your own answer without using the plugin.Unnumbered
I think Uber-jar is a particular implementation of the bundling concept, whereas a fat jar is just the concept itself.Massasauga
It's a bad idea to use fatJar in Gradle as you've described: like this, you will have tons of duplicate dependencies (if there are any). It's better to use proper plugin: github.com/johnrengelman/shadowMarikomaril
M
153

The different names are just ways of packaging Java applications.

Skinny – Contains only the bits you literally type into your code editor, and nothing else.

Thin – Contains all of the above plus the application’s direct dependencies of your application (db drivers, utility libraries, etc.).

Hollow – The inverse of thin. It contains only the bits needed to run your application but does not contain the application itself. Basically a pre-packaged “application server” to which you can later deploy your application, in the same style as traditional Java EE application servers, but with important differences.

Fat/Uber – Contains the bit you literally write yourself plus the direct dependencies of your application PLUS the bits needed to run your application “on its own”.

Source: Article from Dzone

Visual representation of JAR types

Minim answered 21/8, 2019 at 12:54 Comment(5)
Best answer IMO since it also gives comparison to other jar types.Zaratite
Wouldn't hollow be the inverse of skinny rather than thin? The inverse of thin would be none of your code and all the dependencies your code doesn't use. :-)Marrakech
Is java runtime able to support running Fat jar?Gnathonic
@NickWills Yes it shouldMinim
What if I want all my app dependencies as a single jar? What is that called?Blast
U
117

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>
  </pluginRepositories>
<!-- ... -->

<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>
Unnumbered answered 28/4, 2015 at 16:53 Comment(6)
So is "fat jar" just another name for "uber jar"?Kabyle
@Kabyle Yes, exactly.Unnumbered
Why use some third party plugin when there is maven assembly plugin with it's jar-with-dependencies assembly?Merwyn
@Merwyn you can add your own answer without using the plugin.Unnumbered
I think Uber-jar is a particular implementation of the bundling concept, whereas a fat jar is just the concept itself.Massasauga
It's a bad idea to use fatJar in Gradle as you've described: like this, you will have tons of duplicate dependencies (if there are any). It's better to use proper plugin: github.com/johnrengelman/shadowMarikomaril
M
20

Fat jar or uber jar is a jar which contains all project class files and resources packed together with all it's dependencies. There are different methods for achieving such effect:

  • dependencies' jars are copied into main jar and then loaded using special class loader (onejar, spring-boot-plugin:repackage)
  • dependencies' jars are extracted at the top of main jar hierarchy (maven-assembly-plugin with it's jar-with-dependencies assembly)
  • dependencies' jars are unpacked at the top of main jar hierarchy and their packages are renamed (maven-shade-plugin with shade goal)

Below sample assembly plugin configuration jar-with-dependencies:

<project>
  <!-- ... -->
  <build>
    <!-- ... -->
    <plugins>
      <plugin>
        <!-- NOTE: We don't need a groupId specification because the group is
             org.apache.maven.plugins ...which is assumed by default.
         -->
        <artifactId>maven-assembly-plugin</artifactId>
        <version>2.6</version>
        <configuration>
          <descriptorRefs>
            <descriptorRef>jar-with-dependencies</descriptorRef>
          </descriptorRefs>
          <classifier>
        </configuration>
        <!-- ... -->
</project>

For more detailed explanation: Uber-JAR at imagej.net

Merwyn answered 11/4, 2016 at 4:31 Comment(2)
One thing to be careful about with FAT jars: conflicting versions of the same classes, across the different dependency jars. You can get really DIFFERENT (and often very frustrating-go-boom) effects depending on which approach you take (i.e. totally exploding all the jars and then reassembling them into one jar, vs. a jar-of-jars). Neither approach is necessarily better. Most build systems have some sort of "reverse dependency explorer" that can alert you to such version conflicts.Muco
Yes, unpacking multiple jars has some important drawbacks. Another one is the issue with META-INF files like signature files or SPI (services/package.Class) files which are overwritten by assembly plugin by default. Shade plugin has some special transformers which can merge the files if neededMerwyn
M
13

In the case of an executable jar, another way to think about a fat jar is one you can execute by invoking:

java -jar myFatLibrary.jar

without the need for -cp / --classpath, or even double clicking the jar icon.

Massasauga answered 10/7, 2016 at 16:23 Comment(4)
Keep in mind that -jar requires Main-Class header in MANIFEST.MF: docs.oracle.com/javase/tutorial/deployment/jar/run.htmlMerwyn
That's the case even for non-fat jars, so not relevant really.Massasauga
what mvn flag can we use to skip building the fat jar file?Rubdown
By default it won't be fat. You have to explicitly use jar-with-dependencies, uberjar or shadow for mvn install to put anything other than your generated class files in thereMassasauga
L
1

From the Gradle documentation:

In the Java space, applications and their dependencies typically used to be packaged as separate JARs within a single distribution archive. That still happens, but there is another approach that is now common: placing the classes and resources of the dependencies directly into the application JAR, creating what is known as an uber or fat JAR.

Here is a demonstrated of uberJar task in build.gradle file:

task uberJar(type: Jar) {
    archiveClassifier = 'uber'

    from sourceSets.main.output

    dependsOn configurations.runtimeClasspath
    from {
        configurations.runtimeClasspath.findAll { it.name.endsWith('jar') }.collect { zipTree(it) }
    }
}

In this case, we’re taking the runtime dependencies of the project — configurations.runtimeClasspath.files — and wrapping each of the JAR files with the zipTree() method. The result is a collection of ZIP file trees, the contents of which are copied into the uber JAR alongside the application classes.

Lamberto answered 15/10, 2019 at 4:16 Comment(3)
Copied content needs to be much more clearly marked as such. That is, quoted.Formalism
See for example "How to reference material written by others"Formalism
Otherwise, it is plagiarism.Formalism
E
0

A fat jar simply contains same classes as a classical jar + classes from all of their runtime dependencies.

With Jeka ( https://jeka.dev) you can achieve it programmatically :

JkPathTreeSet.of(Paths.get("classes")).andZips(
    Paths.get("bouncycastle-pgp-152.jar"),
    Paths.get("classgraph-4.8.41.jar"),
    Paths.get("ivy-2.4.0.jar")
).zipTo(Paths.get("fat.jar"));

or just by parametring Java plugin :

javaPlugin.getProject().getMaker().defineMainArtifactAsFatJar(true);
Expulsion answered 9/7, 2019 at 16:30 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.