java jar with maven

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 :

  1. Maven 3.1.1
  2. JDK 1.7
  3. 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.

one-jar-folder-structure

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.

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>

		  <!-- 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 :

App.java

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.

pom.xml

<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.

Download Source Code

Download – maven-one-jar-example.zip (6 KB)

References

  1. onejar-maven-plugin official page
  2. Joda Time
  3. How to create a jar file with Maven