Week 112 — What is a fat JAR, how can a developer create one and what are the alternatives?
Question of the Week #112
What is a fat JAR, how can a developer create one and what are the alternatives?
5 Replies
Java libraries are typically packaged as thin JARs meaning that the library code is contained in a JAR file without any of its dependencies. In order to use a library packaged using a thin JAR, one needs to also include the transitive dependencies (typically using their own JARs).
Build tools like Maven or Gradle handle all of that by downloading all direct and transitive dependencies as needed and running the projects including all dependencies.
On the other hand, fat JARs (or uber JARs) are sometimes used for applications in order to package them in a single JAR file. Here, the code of the application and all dependencies used by it are combined into a single JAR file. This means that fat JARs can be run (given a Java runtime environment is installed) without requiring any extra JARs.
However, this shouldn't be used for code that is intended to be used as a library as that can result in the having multiple versions of the same code mixed together in the classpath (or prevents the application from starting due to split packages on the modulepath).
Using fat JARs is also incompatible with JPMS modules.
In Maven, a fat JAR can be created using the
maven-assembly-plugin
using the following configuration:
jar-with-dependependencies
specifies using a fat JAR and adding the main class to the MANIFEST.MF marks it as executable.
Adding the <execution>
binds assembly:single
to the package
phase ensuring that the fat JAR is created when running mvn package
.As an alternative to fat JARs, it is possible to copy all dependencies in a directory and add them to the classpath or modulepath.
With Maven, this can be done using the
mvn dependency:copy-dependencies
command which copies all dependencies to a subdirectory of target
.
Since that requires additional work to set up, the jlink
tool can be used to create a custom JRE containing the necessary modules, dependencies and the application to run.
In order to allow users to install this JRE by downloading a single file, it is possible to use the jpackage
tool which creates an installer for such a Java runtime image. This would then install the necessary JRE, modules and dependencies as well as setting up a shortcut or similar if wanted.
Yet another option is to use the native-image
tool from GraalVM. This allows converting Java applications into native executables that don't require a JRE to run. The native-maven-plugin
can be used to do that automatically:
When that plugin is added to the pom.xml, it is possible to create a native executable using mvn native:compile
.📖 Sample answer from dan1st
Fat Jar is kind of release scenario, sometimes projects likes to give only one JAR which contains all dependencies inside, that is called fat jar,
Other type of delivery is to provide all dependency jars in one folder, that way the app will find all the required jars in the classpath
Fat jars mostly used in desktop app deliveries, because it is easier to download and share, if the app is web app, nobody knows what happens in the server and mostly we release as spring boot or quarkus release all in one folder.
Submission from ozkanpakdil
A "fat JAR" is a deployment artifact created by combining all (or most) application and library code into a single JAR file. This simplifies distribution and execution for standalone executables (e.g. desktop apps, web services, AWS Lambda functions, etc.), because the runtime environment has fewer prerequisites.
Fat JARs are typically created as part of the release process, using a build tool like Maven or Gradle. Each tool will have its own plugins and procedures for building it.
Gradle does have plugins for this task, but can also do it natively, by configuring the
jar
task.
Maven has a few different plugins: maven-assembly-plugin
, maven-shade-plugin
, and onejar-maven-plugin
. Each has its own strengths and weaknesses.Alternatively, an application can bundle only its own code into a JAR, and rely on the runtime environment to contain the necessary libraries. The execution command will need to supply the necessary libraries as part of the classpath.
Applications built on the Java/Jakarta EE stack use a variant of that approach. They are run within an application server, which will load and run the artifact with the necessary dependencies available.
Submission from dangerously_casual