Maven – Create a fat Jar file – One-JAR example
In this tutorial, we will show you how to use Maven build tool, One-JAR plugin to create a single Jar together with its dependency Jars into a single executable Jar file, so called fat Jar.
Tools used :
- Maven 3.1.1
- JDK 1.7
- Joda-time 2.5
1. Create a simple Java project
Create a Java project from the Maven quick start template.
$ mvn archetype:generate -DgroupId=com.mkyong.core.utils -DartifactId=dateUtils
-DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false
The following files and folder structure will be created.
.
|____dateUtils
| |____pom.xml
| |____src
| | |____main
| | | |____java
| | | | |____com
| | | | | |____mkyong
| | | | | | |____core
| | | | | | | |____utils
| | | | | | | | |____App.java
| | |____test
| | | |____java
| | | | |____com
| | | | | |____mkyong
| | | | | | |____core
| | | | | | | |____utils
| | | | | | | | |____AppTest.java
Make it support Eclipse.
$ mvn eclipse:eclipse
Imports the project into Eclipse IDE.
2. Update Pom.xml
Update pom.xml
to declare the jodatime dependencies. For output to a Jar
format, make sure the packaging tag is set to ‘jar’. Read the comments for self-explanatory.
<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>
<!-- Make this jar executable -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifest>
<mainClass>com.mkyong.core.utils.App</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
</plugins>
</build>
</project>
3. Get CurrentDate with JodaTime
Update the generated App.java
with the following content :
package com.mkyong.core.utils;
import org.joda.time.LocalDate;
public class App {
public static void main(String[] args) {
System.out.println(getLocalCurrentDate());
}
//Print current date with JodaTime
private static String getLocalCurrentDate() {
LocalDate date = new LocalDate();
return date.toString();
}
}
4. Jar File
Maven package the project to generate the final Jar file. A new dateutils.jar
is created in the $project/target
folder.
$ mvn package
List out the jar content.
$ jar tf target/dateutils.jar
META-INF/
META-INF/MANIFEST.MF
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
Try to run this Jar file.
$ java -jar dateutils.jar
Exception in thread "main" java.lang.NoClassDefFoundError: org/joda/time/LocalDate
at com.mkyong.core.utils.App.getLocalCurrentDate(App.java:14)
at com.mkyong.core.utils.App.main(App.java:9)
Caused by: java.lang.ClassNotFoundException: org.joda.time.LocalDate
at java.net.URLClassLoader$1.run(URLClassLoader.java:366)
at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
at java.lang.ClassLoader.loadClass(ClassLoader.java:423)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
at java.lang.ClassLoader.loadClass(ClassLoader.java:356)
... 2 more
Above is the expected error message, because the joda-time.jar
is missing.
5. One-Jar Example
Update pom.xml
to use One-Jar plugin, it will create a single Jar together with its dependency Jars.
<project>
<build>
<plugins>
<!-- Includes the runtime dependencies -->
<plugin>
<groupId>org.dstovall</groupId>
<artifactId>onejar-maven-plugin</artifactId>
<version>1.4.4</version>
<executions>
<execution>
<goals>
<goal>one-jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<!-- One-Jar is in the googlecode repository -->
<pluginRepositories>
<pluginRepository>
<id>onejar-maven-plugin.googlecode.com</id>
<url>http://onejar-maven-plugin.googlecode.com/svn/mavenrepo</url>
</pluginRepository>
</pluginRepositories>
</project>
Package it again, two jars will be created in the “target” folder – dateUtils.jar
and dateUtils-one-jar.jar
.
$ mvn package
The dateUtils-one-jar.jar
is the final fat-jar you want, list out the jar content :
$ jar tf target/dateutils.one-jar.jar
META-INF/MANIFEST.MF
main/dateutils.jar
lib/joda-time-2.5.jar
com/
com/simontuffs/
com/simontuffs/onejar/
.version
OneJar.class
com/simontuffs/onejar/Boot$1.class
com/simontuffs/onejar/Boot$2.class
com/simontuffs/onejar/Boot$3.class
com/simontuffs/onejar/Boot.class
com/simontuffs/onejar/Handler$1.class
com/simontuffs/onejar/Handler.class
com/simontuffs/onejar/IProperties.class
com/simontuffs/onejar/JarClassLoader$1.class
com/simontuffs/onejar/JarClassLoader$2.class
com/simontuffs/onejar/JarClassLoader$ByteCode.class
com/simontuffs/onejar/JarClassLoader$FileURLFactory$1.class
com/simontuffs/onejar/JarClassLoader$FileURLFactory.class
com/simontuffs/onejar/JarClassLoader$IURLFactory.class
com/simontuffs/onejar/JarClassLoader$OneJarURLFactory.class
com/simontuffs/onejar/JarClassLoader.class
com/simontuffs/onejar/OneJarFile$1.class
com/simontuffs/onejar/OneJarFile$2.class
com/simontuffs/onejar/OneJarFile.class
com/simontuffs/onejar/OneJarURLConnection.class
src/
src/com/
src/com/simontuffs/
src/com/simontuffs/onejar/
src/OneJar.java
src/com/simontuffs/onejar/Boot.java
src/com/simontuffs/onejar/Handler.java
src/com/simontuffs/onejar/IProperties.java
src/com/simontuffs/onejar/JarClassLoader.java
src/com/simontuffs/onejar/OneJarFile.java
src/com/simontuffs/onejar/OneJarURLConnection.java
doc/
doc/one-jar-license.txt
One-Jar plugin puts the runtime dependencies in the lib
folder, for example lib/joda-time-2.5.jar
, and the main jar in the main
folder, for example main/dateutils.jar
. In additional, it also creates many simontuffs classes to help loads the included Jars correctly.
Try to run the final fat-jar.
$ java -jar dateutils.one-jar.jar
2014-10-18
Done.
This should be discouraged in favour of the maven-assembly-plugin which, in contrast, is officially maintained and released to Central.
If you need more control to avoid clashes, the maven-shade-plugin is again official and maintained, unlike onejar.
is it like maven-assembly-plugin ?
The way it “JAR” the project dependencies is different. The main problem of assembly is if your project has many dependencies it may cause name override issue, in this case, give one-jar a try 🙂
https://code.google.com/p/onejar-maven-plugin/
Nice tutorial.
For the past few days I’ve been trying, without success, to create a jar with my dependencies which includes some native libraries from http://sigar.hyperic.com.
Could you try this yourself?
Thank you for your work.
Not sure what to try, refer to this one-jar usage page – http://onejar-maven-plugin.googlecode.com/svn/mavensite/usage.html
To include native libraries, you need to define
${project.build.directory}/dllextract
test.dll