Create a fat Jar file – Maven Shade Plugin
In this tutorial, we will show you how to use Maven Shade Plugin to create a Jar together with its dependency Jars into a single executable Jar file, so called fat Jar or uber Jar.
Note
Maven Shade plugin is a better plugin to create fat/uber jar, if compare with assembly plugin, because it provides class relocating feature, to avoid same class name conflict in the classpath.
Maven Shade plugin is a better plugin to create fat/uber jar, if compare with assembly plugin, because it provides class relocating feature, to avoid same class name conflict in the classpath.
1. Review a Java project
Previous Java project (dateutils) will be reused, see following folder structure
Note
This project has a single dependency –
This project has a single dependency –
joda-time.jar
2. Pom.xml
Read below comment for self-explanatory.
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.mkyong.core.utils</groupId>
<artifactId>dateUtils</artifactId>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<name>dateUtils</name>
<url>http://maven.apache.org</url>
<properties>
<jdk.version>1.7</jdk.version>
<jodatime.version>2.5</jodatime.version>
<junit.version>4.11</junit.version>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<version>${jodatime.version}</version>
</dependency>
</dependencies>
<build>
<finalName>dateutils</finalName>
<plugins>
<!-- download source code in Eclipse, best practice -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-eclipse-plugin</artifactId>
<version>2.9</version>
<configuration>
<downloadSources>true</downloadSources>
<downloadJavadocs>false</downloadJavadocs>
</configuration>
</plugin>
<!-- Set a compiler level -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>${jdk.version}</source>
<target>${jdk.version}</target>
</configuration>
</plugin>
<!-- Maven Shade Plugin -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.3</version>
<executions>
<!-- Run shade goal on package phase -->
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<!-- add Main-Class to manifest file -->
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>com.mkyong.core.utils.App</mainClass>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
3. Package It
To produces the final Jar, just package it :
$ mvn package
[INFO]
[INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ dateUtils ---
[INFO] Building jar: /Users/mkyong/dateUtils/target/dateutils.jar
[INFO]
[INFO] --- maven-shade-plugin:2.3:shade (default) @ dateUtils ---
[INFO] Including joda-time:joda-time:jar:2.5 in the shaded jar.
[INFO] Replacing original artifact with shaded artifact.
[INFO] Replacing /Users/mkyong/dateUtils/target/dateutils.jar with /Users/mkyong/dateUtils/target/dateUtils-1.0-SNAPSHOT-shaded.jar
[INFO] Dependency-reduced POM written at: /Users/mkyong/dateUtils/dependency-reduced-pom.xml
[INFO] Dependency-reduced POM written at: /Users/mkyong/dateUtils/dependency-reduced-pom.xml
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 3.594s
[INFO] Finished at: Tue Oct 21 15:24:28 MYT 2014
[INFO] Final Memory: 17M/42M
[INFO] ------------------------------------------------------------------------
Two jar files will be created in the target
folder.
- dateutils.jar – Project and dependency classes in a single jar, this is what you want.
- original-dateutils.jar – Only your project classes
P.S The generated dependency-reduced-pom.xml
is for reference only, just ignore it.
4. Review It
List out the content of dateutils.jar
$ jar tf target/dateutils.jar
META-INF/MANIFEST.MF
META-INF/
com/
com/mkyong/
com/mkyong/core/
com/mkyong/core/utils/
com/mkyong/core/utils/App.class
META-INF/maven/
META-INF/maven/com.mkyong.core.utils/
META-INF/maven/com.mkyong.core.utils/dateUtils/
META-INF/maven/com.mkyong.core.utils/dateUtils/pom.xml
META-INF/maven/com.mkyong.core.utils/dateUtils/pom.properties
META-INF/LICENSE.txt
META-INF/NOTICE.txt
org/
org/joda/
org/joda/time/
org/joda/time/base/
org/joda/time/base/AbstractDateTime.class
org/joda/time/base/AbstractDuration.class
//...
org/joda/time/Weeks.class
org/joda/time/YearMonth$Property.class
org/joda/time/YearMonth.class
org/joda/time/YearMonthDay$Property.class
org/joda/time/YearMonthDay.class
org/joda/time/Years.class
META-INF/maven/joda-time/
META-INF/maven/joda-time/joda-time/
META-INF/maven/joda-time/joda-time/pom.xml
META-INF/maven/joda-time/joda-time/pom.properties
MANIFEST.MF
Manifest-Version: 1.0
Build-Jdk: 1.7.0_05
Built-By: mkyong
Created-By: Apache Maven 3.1.1
Main-Class: com.mkyong.core.utils.App
Archiver-Version: Plexus Archiver
Run it
$ java -jar target/dateutils.jar
2014-10-21
Download Source Code
Download it – dateUtils-maven-shade-plugin.zip (10 KB)
hi ,
As i see, shaded plugin will create two jars
1. dateutils.jar
2. original-dateutils.jar
Can we avoid of creating the original-dateutils.jar.
We have a requirement in which we need only the uber jar.
I have some third party jars which are not part of central repo that i need to include in the executable jar. Currently I have then under project base directory. It seems Maven assembly and shade plugin doesn’t include external dependencies in fat jar. Could you please help if it is possible to build executable jar which is having external libraries included?
apparently some of the dependent jars are signed and when they get sharded to fat jar java complains of a security error. So I can use the maven signing plugin, but not sure what is best way any thoughts or is there any way to have direct integration with the shard plugin?
Thanks for your instruction. Regarding to “mvn package”, when I ran this command in the window 10 then I got this error message.
C:\Users\SK\Documents\NetBeansProjects>mvn package
‘mvn’ is not recognized as an internal or external command,
operable program or batch file.
I am using Netbeans 11. Is there a way to run the “mvn package” inside the netbeans?
I also built the project. The project made a fat jar. But, when I run the jar file, I got this error message:
Error: A JNI error has occurred, please check your installation and try again
Exception in thread “main” java.lang.SecurityException: Invalid signature file digest for Manifest main attributes
at java.base/sun.security.util.SignatureFileVerifier.processImpl(SignatureFileVerifier.java:335)
at java.base/sun.security.util.SignatureFileVerifier.process(SignatureFileVerifier.java:268)
at java.base/java.util.jar.JarVerifier.processEntry(JarVerifier.java:316)
at java.base/java.util.jar.JarVerifier.update(JarVerifier.java:230)
at java.base/java.util.jar.JarFile.initializeVerifier(JarFile.java:758)
at java.base/java.util.jar.JarFile.ensureInitialization(JarFile.java:1035)
at java.base/java.util.jar.JavaUtilJarAccessImpl.ensureInitialization(JavaUtilJarAccessImpl.java:69)
at java.base/jdk.internal.loader.URLClassPath$JarLoader$2.getManifest(URLClassPath.java:873)
at java.base/jdk.internal.loader.BuiltinClassLoader.defineClass(BuiltinClassLoader.java:807)
at java.base/jdk.internal.loader.BuiltinClassLoader.findClassOnClassPathOrNull(BuiltinClassLoader.java:719)
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClassOrNull(BuiltinClassLoader.java:642)
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:600)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
at java.base/java.lang.Class.forName0(Native Method)
at java.base/java.lang.Class.forName(Class.java:416)
at java.base/sun.launcher.LauncherHelper.loadMainClass(LauncherHelper.java:760)
at java.base/sun.launcher.LauncherHelper.checkAndLoadMain(LauncherHelper.java:655)
I guess that it is related to the security files which I need to remove from each jar.
Do you have any advice on how to fix it out?
Here is my pom.xml file:
4.0.0
com.mycompany
FSPFoodPriceMonitoring
1.0-SNAPSHOT
jar
UTF-8
13
13
com.google.maps
google-maps-services
0.9.3
com.opencsv
opencsv
4.0
mysql
mysql-connector-java
5.1.21
org.apache.poi
poi
4.1.2
commons-net
commons-net
3.3
commons-io
commons-io
2.4
com.sun.mail
javax.mail
1.6.0
org.jsoup
jsoup
1.13.1
org.glassfish
javax.json
1.0.4
org.apache.tika
tika-parsers
1.24
org.apache.tika
tika-core
1.24
net.sourceforge.htmlunit
htmlunit
2.40.0
FSPFoodPriceMonitoring
org.apache.maven.plugins
maven-eclipse-plugin
2.9
true
false
org.apache.maven.plugins
maven-compiler-plugin
2.3.2
<!– I removed this because of an error message
${jdk.version}
${jdk.version}
–>
org.apache.maven.plugins
maven-shade-plugin
2.3
package
shade
fsp.FSPFoodpriceMonitoringMain
thanks mkyong! really helpful
Hi,
I have created a thin jar for my project with no external dependencies and used maven-dependency-plugin with copy-dependencies as a goal so running maven copy command downloads all the required jars into the selected folder. But now I need to create a semi-fat jar with the selected dependencies within the main jar and exclude all the other remaining jars. Also is it possible to keep the main jar as thin jar only and keep the selected jars in a folder inside the target folder and keep the other jars in a separate folder?
I am trying to include a third party jar (this is not in rep!) in the dateutils.jar file that the above creates. But it is not getting included.
I did: (i) created “lib” folder under the basedir of project and copied “includeMe.jar” in it and (ii) Edited pom.xml like below:
Not sure what I am missing.
Thanks
Edited pom.xml:
Under
…
com.my.test
includeMe
1.0.0.0-SNAPSHOT
system
${basedir}/lib/includeMe.jar
Hi Daitri,
You can achieve this by following these steps :
1) Create a jar using shade plugin, dont include property file in the jar.
2) getResourceAsStream is not required if the file is in the same location as the jar file, use new File(“fileName.extn”);
Check if the jar file is containing all the files you need by opening it in a decompiler, eg JDGui
I have an uber jar that I am executing with java -jar option, but I also have a requirement to specify -cp option with that command. However, java program is not passing along the value I specify with -cp option to the ClassLoader. How can I make sure that java program passes along the value specified with -cp option to the ClassLoader? I am trying read a properties file from the location specified in the -cp option using the getResourceAsStream method which is failing currently because of this……Any help is much appreciated