It’s very common that we might need to create a Java application and generate the jar executable, but we need to use third-party libraries that are also needed as part of our application. So, one solution for that scenario is to create a fat/uber jar.
Basically, a fat/uber jar is a self-sufficient file that contains all the classes and dependencies to run the application. In other words, a unique jar that contains everything, therefore, we don’t need to take care of sharing, copying and placing third party libraries with out executable.
This approach is very useful for desktop applications and also to micro-services in Java.
Maven
With maven, we can achieve that using the plugin maven-shade-plugin
and to the phase package
we set the goal shade
. Optionally, using the same plugin we can indicate the main class for the application.
<project> <dependencies> ... </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> <version>3.2.4</version> <executions> <execution> <phase>package</phase> <goals> <goal>shade</goal> </goals> <configuration> <transformers> <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"> <mainClass>com.orthanc.mypackage.Main</mainClass> </transformer> </transformers> </configuration> </execution> </executions> </plugin> </plugins> </build> </project>
Gradle
With Gradle is even easier, we only need to use the jar
plugin included as part of the tool. Optionally, we can also indicate the main-class
for our application.
dependencies { //my dependencies } jar { from { configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) } } manifest { attributes "Main-Class": "com.orthanc.mypackage.Main" } }
There are some snipped code on internet and stackOverflow using configurations.compile.collect
. However it doesn’t work properly with the transitive and module dependencies, when the dependency is added using implementation
or api
instead of compile
. Gradle 6 has marked the compile
scope as deprecated and Gradle 7 is not supporting it anymore.
Therefore, using configurations.runtimeClasspath.collect
is a better approach and includes the transitive and module dependencies.
References
- https://www.baeldung.com/gradle-fat-jar
- http://maven.apache.org/plugins/maven-shade-plugin/plugin-info.html