Main Tutorials

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 Author

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

Comments

Subscribe
Notify of
40 Comments
Most Voted
Newest Oldest
Inline Feedbacks
View all comments
Ankit Sharma
4 years ago

Hello Sir,

I am trying to create a jar file from the root directory which is your project starting point not for the src/main/java.
Can you share the maven plugin which can handle or to create jart file from the root one as we have testData folder also or we have TestScrenshot folder.

If you need any more details please let me know.

Ankit Sharma

Kaustav Sarkar
4 years ago
Reply to  Ankit Sharma

You can provide source directory and test directory in the pom.xml inside build tag. Something like this:
//unable to write angular brackets. So putting slashes instead
//build
//sourceDirectory src/main/java/ //sourceDirectory
//testDirectory src/test/java/ //testDirectory
//build

Ponni Priyadharshni
7 years ago

Thanks, helped me understand things clearly!

Yiannis
11 years ago

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

Cheers!

mkyong
9 years ago
Reply to  Yiannis

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

Ankan
10 years ago
Reply to  mkyong

What will be the settings.xml for this example ?

David
11 years ago
Reply to  mkyong

Here is also nice fresh post about maven one jar: http://java.dzone.com/articles/simple-powerful-concept

Thank you for many usefull blog post!

Yiannis
11 years ago
Reply to  mkyong

Yes, I have used it for making executable jars. I think its configuration is easier.
However when I create my own jar library (with no main method) which depends on other libraries, I use the Maven Shade Plugin http://maven.apache.org/plugins/maven-shade-plugin/

Robthekilla
2 years ago

I needed help building a source code I found

asam
3 years ago

Congratulations. Your explanations are clear and more important, correct!

Raj
4 years ago

Hi,
I have two source codes, one is a library jar and the other is an executable jar that depends on that library jar. I want to have both the source files in the same eclipse project. How to do that ? Any ideas will be appreciated.

venky
4 years ago

nice tutorial
MANIFEST.MF needs update with classpath of dependencies.

Added the following line:

org.apache.maven.plugins
maven-jar-plugin

**/log4j.properties


com.oracle.dbtools.App
true <======
dependency-jars/

Alexander D Mills
5 years ago

This needs to be a git repo so it can kept up to date and clone easily!

juanmaflow
8 years ago

Thanks!! Best tutorial I’ve found 🙂

Farhad Tarapore
8 years ago

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.

Rishi
8 years ago

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.

Kaustav Sarkar
4 years ago
Reply to  Rishi

You would need to find a plugin for creating a fat jar.
https://www.mkyong.com/maven/create-a-fat-jar-file-maven-assembly-plugin/

Thinh Nguyen
9 years ago

Nice tutorial. Thank you.

praveen
9 years ago

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

mkyong
9 years ago
Reply to  praveen

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

aimmoth
9 years ago

Great!

Adam Lee
9 years ago

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
9 years ago
Reply to  Adam Lee
Pankaj Pandey
9 years ago

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
9 years ago
Reply to  Pankaj Pandey

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

Dev
9 years ago

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
9 years ago
Reply to  Dev
Quinn Carver
9 years ago

invaluable, thank you

Al Wells
10 years ago

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
10 years ago

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
9 years ago
Reply to  Carl

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

deevan
10 years ago

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
9 years ago
Reply to  deevan
monireh jamshidi
10 years ago

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
11 years ago

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

DucQuoc.wordpress.com
11 years ago

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
9 years ago

Thanks for your inputs.

birinhos
6 years ago

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
8 years ago

fuck maven, god