187

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

Yves M.
  • 29,855
  • 23
  • 108
  • 144
erwaman
  • 3,307
  • 3
  • 28
  • 29
  • 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. – nishu Oct 03 '13 at 04:34
  • @Nadeem_MK http://meta.stackexchange.com/questions/5280/embrace-the-non-googlers http://meta.stackexchange.com/questions/8724/how-should-we-deal-with-google-questions – eis Oct 03 '13 at 06:47
  • 2
    The original answer was pointing to this link: http://www.javacodegeeks.com/2012/11/packing-your-java-application-as-one-or-fat-jar.html – George Stocker Oct 30 '14 at 10:46
  • 3
    I wonder if a fat jar is the java equivalent of static linking in c – Sridhar Sarnobat Jul 23 '17 at 20:44
  • @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. – Rob Wells Apr 21 '22 at 16:06

6 Answers6

142

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

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Mark Han
  • 2,785
  • 2
  • 16
  • 31
115

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>
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Dmitry Ginzburg
  • 7,391
  • 2
  • 37
  • 48
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

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
MeTTeO
  • 2,088
  • 16
  • 19
  • 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. – Charles Roth Feb 14 '19 at 18:51
  • 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 needed – MeTTeO Feb 12 '20 at 09:01
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.

Sridhar Sarnobat
  • 25,183
  • 12
  • 93
  • 106
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.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
roottraveller
  • 7,942
  • 7
  • 60
  • 65
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);