How to create a jar file with Maven

java jar with maven

In this tutorial, we will show you how to use Maven build tool, to create a single executable Jar, and how to deal with the project’s dependencies.

Tools used :

  1. Maven 3.1.1
  2. JDK 1.7
  3. log4j 1.2.17
  4. Joda-time 2.5
  5. Eclipse 4.3

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

Above folder structure is not enough, create a log4j.properties file and put it in src/main/resources/log4j.properties, just create the resources folder manually.

log4j.properties

# Root logger option
log4j.rootLogger=DEBUG, stdout
 
# Direct log messages to stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n

Make it support Eclipse.


$ mvn eclipse:eclipse

And imports the project into Eclipse IDE, the final project structure should be like this :

maven-create-a-jar

2. Update Pom.xml

Update pom.xml to declare both log4j and the jodatime dependencies, for output to a jar format, make sure the packaging is set to “jar”. 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>
	
	<!-- Output to jar format -->
	<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>
		<log4j.version>1.2.17</log4j.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>
		<dependency>
			<groupId>log4j</groupId>
			<artifactId>log4j</artifactId>
			<version>${log4j.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 JDK 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>
				  <!-- DO NOT include log4j.properties file in your Jar -->
				  <excludes>
					<exclude>**/log4j.properties</exclude>
				  </excludes>
				  <archive>
					<manifest>
						<!-- Jar file entry point -->
						<mainClass>com.mkyong.core.utils.App</mainClass>
					</manifest>
				  </archive>
				</configuration>
			</plugin>

		</plugins>
	</build>

</project>

3. Update App.java

Update the generated App.java with the following content :

App.java

package com.mkyong.core.utils;

import org.apache.log4j.Logger;
import org.joda.time.LocalDate;

public class App {

	private static final Logger logger = Logger.getLogger(App.class);

	public static void main(String[] args) {
		System.out.println(getLocalCurrentDate());
	}

	private static String getLocalCurrentDate() {

		if (logger.isDebugEnabled()) {
			logger.debug("getLocalCurrentDate() is executed!");
		}

		LocalDate date = new LocalDate();
		return date.toString();

	}

}

Now, this project has two dependencies : log4j and jodatime.

4. Working with Dependencies

4.1. How can I add dependencies in a jar?

– You can put both log4j.jar and jodatime.jar inside the final.jar, but your classes are unable to call other classes which is inside the unpack log4j.jar, Java jar is designed like this, unless you create a special class loader like one-jar plugin.

– Alternatively, use maven-assembly-plugin to extract all dependency jars into raw classes, and group it together. Read this StackOverflow thread. This hack is workable in project with less dependencies only, for large project with many dependencies, it will cause Java class name conflict issue.

– Try one-jar plugin, it will create a fat-jar, which includes the entire project’s dependencies into a single jar file, read this article – Create a fat Jar file with Maven

4.2 Solution
The one-jar solution is really good, but I don’t like the custom class loader and fat-jar concept. My simplest and always working solution is copy the entire project’s dependencies to a pre-defined folder, and define the dependency classpath in the jar’s manifest file.

Below is the updated and final pom.xml, to use maven-dependency-plugin to copy all dependencies to target/dependency-jars/ folder, and use maven-jar-plugin to add the dependency classpath.

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>
		<log4j.version>1.2.17</log4j.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>
		<dependency>
			<groupId>log4j</groupId>
			<artifactId>log4j</artifactId>
			<version>${log4j.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>
				  <excludes>
					<exclude>**/log4j.properties</exclude>
				  </excludes>
				  <archive>
				    <manifest>
					<addClasspath>true</addClasspath>
					<mainClass>com.mkyong.core.utils.App</mainClass>
					<classpathPrefix>dependency-jars/</classpathPrefix>
				    </manifest>
				  </archive>
				</configuration>
			</plugin>

			<!-- Copy project dependency -->
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-dependency-plugin</artifactId>
				<version>2.5.1</version>
				<executions>
				  <execution>
					<id>copy-dependencies</id>
					<phase>package</phase>
					<goals>
						<goal>copy-dependencies</goal>
					</goals>
					<configuration>
					  <!-- exclude junit, we need runtime dependency only -->
					  <includeScope>runtime</includeScope>
					  <outputDirectory>${project.build.directory}/dependency-jars/</outputDirectory>
					</configuration>
				  </execution>
				</executions>
			</plugin>

		</plugins>
	</build>

</project>

5.The final Jar file

5.1 Package the project.


$ mvn package

Review the folder structure in the target folder

maven-create-jar-dependency-jars

A dateutils.jar is created, and the entire project runtime dependencies (excluded junit) are copied to target/dependency-jars/ folder.

5.2 List out the dateutils.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

5.3 Extracts and review the content of MANIFEST.MF, the dependencies are added in the Class-Path.

META_INF/MANIFEST.MF

Manifest-Version: 1.0
Built-By: mkyong
Build-Jdk: 1.7.0_05
Class-Path: dependency-jars/joda-time-2.5.jar dependency-jars/log4j-1.2.17.jar
Created-By: Apache Maven 3.1.1
Main-Class: com.mkyong.core.utils.App
Archiver-Version: Plexus Archiver

5.4 Run it


$ java -jar target/dateutils.jar 

log4j:WARN No appenders could be found for logger (com.mkyong.core.utils.App).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
2014-10-19

Oppss…

5.5 Where is log4j.properties?
This is a GOOD practice to exclude the log4j.properties in the jar file, to avoid issues like multiple log4j.properties files in classpath.

You can still pass in the log4j properties via the log4j.configuration system property like this :


$ java -jar -Dlog4j.configuration=file:/full_path/log4j.properties target/dateutils.jar 

17:09:15,385 DEBUG App:18 - getLocalCurrentDate() is executed!
2014-10-19														
Note
In future, if you want to move dateUtils.jar, make sure to copy its dependency-jars folder as well. If you have a better idea, do share with me, thanks.

Done.

Download Source Code

Download – maven-create-a-jar.zip (7 KB)

References

  1. dependency:copy-dependencies
  2. Maven-archetype-plugin official page.
  3. How to make an executable jar file
  4. One-JAR
  5. Maven – Exclude log4j.properties in Jar file
  6. Maven – Create a fat Jar file – One-JAR example

About the Author

author image
mkyong
Founder of Mkyong.com, love Java and open source stuff. Follow him on Twitter, or befriend him on Facebook or Google Plus. If you like my tutorials, consider make a donation to these charities.

Comments

Leave a Reply

avatar
newest oldest most voted
juanmaflow
Guest
juanmaflow

Thanks!! Best tutorial I’ve found :)

Farhad Tarapore
Guest
Farhad Tarapore

What about the case when the app has config file like config.properties? I would not want to put it inside the jar since I may need to change the config for different environments.

Ponni Priyadharshni
Guest
Ponni Priyadharshni

Thanks, helped me understand things clearly!

Rishi
Guest
Rishi

I converted an eclipse project https://github.com/RishiGupta12/serial-communication-manager into maven project using eclipse IDE. Now when running mvn clean install, the jar file generated by maven does not contain lib folder. How to tell maven to include lib folder when building jar.

Thinh Nguyen
Guest
Thinh Nguyen

Nice tutorial. Thank you.

praveen
Guest
praveen

I don’t want to use default project structure given by maven.In that case how to create pom..xml

mkyong
Guest
mkyong

pom is just a xml file, just create it with your favor text editor.

aimmoth
Guest
aimmoth

Great!

Adam Lee
Guest
Adam Lee

I just wanted to add that if you want all run-time dependency jars copied into the dependency-jars folder, you should exclude the includeGroupIds tag from the maven-dependency-plugin.

mkyong
Guest
mkyong
Pankaj Pandey
Guest
Pankaj Pandey
Just add this in pom.xml. It works great org.apache.maven.plugins maven-shade-plugin package shade HelloWorld com.abc.HelloWorld.java 1
mkyong
Guest
mkyong

Thanks, next time, I should try maven-shade-plugin

Dev
Guest
Dev

please tell the way if we want the libs present in the dependencies folder to be inside the jar file instead of the folder at the same level of the jar.

mkyong
Guest
mkyong
Quinn Carver
Guest
Quinn Carver

invaluable, thank you

Al Wells
Guest
Al Wells

Very good. Great that you offer more than one solution to the problem at hand. One-Jar looks great too and I had not heard about it before seeing this post. For now, I’m going to use the Maven approach since I’m all set up with Maven and just want a quick single package solution. But, I also look forward to learning about One-Jar now as it seems it has a lot of valid features too. Thanks so much for the excellent tutorial!

Carl
Guest
Carl

Hello.

Nice tutorial!!
I have a question, why do you write in the pom.xml the next property?

1.6

I think this is to indicate that jdk 1.6 is needed, but I don’t sure.

Thank you very much.

mkyong
Guest
mkyong

Article is updated to use 1.7, yes this is JDK compiler level.

deevan
Guest
deevan

Hello,

I tried using the pom configuration for jar with dependencies, which is creating the jar along with dependencies(manifest) and dependency-jars folder beside the artifact.jar. Is it possible to place all the dependency jars inside the artifact.jar?

Thanks,
Deevan

mkyong
Guest
mkyong
monireh jamshidi
Guest
monireh jamshidi

hello,
i want to use tag file java that is been .jar in maven project…
i do it and from it tag file project make .jar and i put that jar file in pom file project maven dependency …
but i can not see tag file

monireh jamshidi
Guest
monireh jamshidi

hello,
i want to use tag file java that is been .jar in maven project…

trackback
How to create a manifest file with Maven

[…] How to create a Jar file with Maven Tags : manifest maven mkyong Founder of Mkyong.com, love Java and open source stuffs. Follow him on Twitter, or befriend him on Facebook or Google Plus. Btw, Mkyong.com is hosted on Liquid Web, a perfect hosting provider, 100% uptime and 24 hours support. […]

DucQuoc.wordpress.com
Guest
DucQuoc.wordpress.com

Thanks for sharing nice tips.

You can also use maven-assembly-plugin or maven-shade-plugin to create a JAR which can be executable and including dependent classes.
http://ducquoc.wordpress.com/2012/03/03/apache-maven-tips/

–Duc

mkyong
Guest
mkyong

Thanks for your inputs.

Yiannis
Guest
Yiannis

Great stuff! Nice tutorial!
Do you think it would be worth mentioning the onejar plugin for executable jars with maven?

Cheers!

mkyong
Guest
mkyong

I created a fat-jar example with one-jar plugin – http://www.mkyong.com/maven/maven-create-a-fat-jar-file-one-jar-example/

birinhos
Guest
birinhos

this is crazy just to build a JAR file and include dependencies ! crazy… there must be a simple way (I am use to go to eclipse and just export to JAR. Now I have one “maven project ” that I want to include in my “normal” project and I just can’t do it because of dependencies … Just to install one simple plugin -maven-assembly-plugin- in maven is crazy) .. I do not understand yet why maven exist … geeks like to complicate things …

oo
Guest
oo

fuck maven, god