Gradle – Create a Jar file with dependencies
In this tutorial, we will show you how to use Gradle build tool to create a single Jar file with dependencies.
Tools used :
- Gradle 2.0
- JDK 1.7
- Logback 1.1.2
1. Project Directory
Create following project folder structure :
By default, Gradle is using the standard Maven project structure.
- ${Project}/src/main/java/
- ${Project}/src/main/resources/
- ${Project}/src/test/java/
2. Java Files
A single Java file to print out the current date time, and logs the message with logback.
DateUtils.java
package com.mkyong;
import java.util.Date;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class DateUtils{
private static final Logger logger = LoggerFactory.getLogger(DateUtils.class);
public static void main(String[] args) {
logger.debug("[MAIN] Current Date : {}", getCurrentDate());
System.out.println(getCurrentDate());
}
private static Date getCurrentDate(){
return new Date();
}
}
logback.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<layout class="ch.qos.logback.classic.PatternLayout">
<Pattern>
%-5level %logger{36} - %msg%n
</Pattern>
</layout>
</appender>
<root level="debug">
<appender-ref ref="STDOUT" />
</root>
</configuration>
3. build.gradle
A build.gradle
sample to create a Jar file along with its logback dependencies.
build.gradle
apply plugin: 'java'
apply plugin: 'eclipse'
version = '1.0'
sourceCompatibility = 1.7
targetCompatibility = 1.7
//create a single Jar with all dependencies
task fatJar(type: Jar) {
manifest {
attributes 'Implementation-Title': 'Gradle Jar File Example',
'Implementation-Version': version,
'Main-Class': 'com.mkyong.DateUtils'
}
baseName = project.name + '-all'
from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } }
with jar
}
//Get dependencies from Maven central repository
repositories {
mavenCentral()
}
//Project dependencies
dependencies {
compile 'ch.qos.logback:logback-classic:1.1.2'
}
4. Create a Jar File
Clean the project.
$ gradle clean
Run the Gradle fatJar
task.
$ gradle fatJar
:compileJava
:processResources
:classes
:fatJar
BUILD SUCCESSFUL
Total time: 6.4 secs
The Jar is created under the $project/build/libs/
folder.
5. Run It
Run it – java -jar hello-all-1.0.jar
.
$Project\build\libs> java -jar hello-all-1.0.jar
16:22:13,249 |-INFO in ch.qos.logback.classic.LoggerContext[default] - Could NOT find resource [logback.groovy]
16:22:13,249 |-INFO in ch.qos.logback.classic.LoggerContext[default] - Could NOT find resource [logback-test.xml]
//...
DEBUG com.mkyong.DateUtils - [MAIN] Current Date : Wed Aug 27 16:22:13 SGT 2014
Wed Aug 27 16:22:13 SGT 2014
Done.
Download Source Code
Download It – gradle-create-single-jar.zip (1.4 KB)
Compile configuration is deprecated for long now, kindly update:
from { configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) } }
It’s really useful for me, thanks
do you have an example for that
For me this did work better:
jar {
manifest {
attributes "Main-Class": application.mainClassName
}
from {
// filters only existing and non-empty dirs
sourceSets.main.runtimeClasspath
.filter { (it.isDirectory() && it.listFiles().length > 0) || it.isFile() }
.collect { it.isDirectory() ? it : zipTree(it) }
}
}
Doesn’t work. I get “no main manifest attribute, in gradle-create-single-jar-all-1.0.jar” with the uploaded example.
I think this is much better:http://www.gradle.org/docs/current/userguide/application_plugin.html
just add this lines to build.gradle:
apply plugin: ‘application’
mainClassName = “com.mkyong.DateUtils”
and then run gradle task:
$ gradle distZip
It’s better, because:
1. This is plugin and your build.gradle much cleaner.
2. This distribute only runtime deps, not compile and test.
3. This will be maintained by plugin contributers.
Yes, but it isn’t a jar. I know a jar file is just a zip file… but the distZip task creates a zip file without a manifest and other jar related things. So, it’s not the same.
This! So much cleaner!
Thank you for the tip
After hours of google searching, you were the saving grace! Thank you so much
I use the shadowjar!!!
shadowJar {
configurations = [project.configurations.compile]
classifier = null
baseName = ‘MyNewJARFileName’
version = null
}
Is there a way to store all the dependencies in one folder in jar, e.g. /libs ?
Yes, with this http://www.gradle.org/docs/current/userguide/application_plugin.html and distZip.
java.lang.StackOverflowError (no error message)
You only need the application plugin and setting up the path build
jar {
from {
configurations.runtimeClasspath.filter{ it.exists() }.collect { it.isDirectory() ? it : zipTree(it) }
}
}
This is also a problem from gradle itself to not making a native way (or some plugin or tasks) to handle this.
Thread: https://discuss.gradle.org/t/include-transitive-dependencies-in-jar/38926
Thanks guys, it solved my problems. You saved my nightmare
Hi mkyong, I’m working on a Test Project which has code under “main” folder and tests under “test” folder. I need to create a single executable jar which contains code from both main and test folders including the necessary dependencies.
The have posted the question on Stackoverflow too with my build.gradle file
StackoverFlow_Link
i kept getting this error when i run the jar file. do you know how to solve it?
Error: Could not find or load main class
Hi Trisia, I have the same ‘Error: Could not find or load main class’ issue when running the compiled jar file. wonder if u have managed to solve it?
Thanks for all your hard work! I’ve been learning from you for years!
In this particular case, your solution for getting fat jars worked great for me.
I was wondering, though (as someone commented on this problem below), how would we make the fatJar task automagically happen as part of the build (or right afterwards).
Yes, I know that it is easy enough to do:
gradle clean build fatJar -info
but I would like to save myself the six characters (plus the bigger task of remembering).
Thanks!
I get class not found error if my main class is in test folder, works fine if main class is in src/main/java. Any suggestions.
Thank you so much for this.
What if you have a LOT of dependencies, but only what to include certain ones, and NOT all of them? I’ve seen examples where that show including one of many dependencies, but not several of many (but not all) dependencies.
Thanks for the solution. Really helpful.
You always give just enough to force us to use our heads to figure out the rest. Thank you!
For people that are adding signed third part jars. Make sure to add this exclude line in the gradle.build file!
exclude ‘META-INF/*.RSA’, ‘META-INF/*.SF’,’META-INF/*.DSA’
`Works perfectly. Thank you Mkyong
https://stackoverflow.com/questions/37848553/error-in-executing-the-generated-jar-file/37848829
For me at first it didn’t work. I spent ages trying to figure out why it wasn’t working and eventually I realised I was supposed to do “gradle fatJar” not “gradle build” – it does say it in the tutorial but perhaps like many others I am often in too much of a hurry for my own good. Thanks.
group ‘br.com.teste.teste’
version ‘1.0’
apply plugin: ‘java’
apply plugin: ‘application’
mainClassName = “br.com.teste.Main”
sourceCompatibility = 1.8
targetCompatibility = 1.8
apply plugin: ‘com.github.johnrengelman.shadow’
shadowJar {
configurations = [project.configurations.compile]
classifier = null
baseName = ‘MyTesteJARFilenameHere’
version = null
}
buildscript {
repositories {
jcenter()
}
dependencies {
classpath ‘com.github.jengelman.gradle.plugins:shadow:2.0.2’
}
}
repositories {
mavenCentral()
}
task execute(type: JavaExec) {
main = “br.com.teste.Main”
classpath = sourceSets.main.runtimeClasspath
systemProperties System.getProperties()
args System.getProperty(“exec.args”, “”).split()
}
sourceSets {
main {
java {
srcDirs = [‘src/main/java’]
}
resources {
srcDirs = [‘src/main/resources’]
}
}
test {
java {
srcDirs = [‘src/test/java’]
}
resources {
srcDirs = [‘src/test/resources’]
}
}
}
dependencies {
testCompile group: ‘junit’, name: ‘junit’, version: ‘4.12’
}
Great Job!
mkyong, your example only works in some cases. I used it on my project with a dependency on javaee and jersey and I ended up with a jar with multiple entries with the same name… and Java doesn’t like it when running in a webstart application. But thanks anyway, I’ve gotten a ton of useful information from you blog in the past!!! When I see it in a Google search I think “ah, that’s good, I trust this guy” 😉
Thanks for the short tutorial. This seems to be way to complicated as compared to maven. Since we just need to use a assembly or onejar plugin.
You are correct. Gradle is considerably more complicated than Maven, and therefore has a steeper learning curve (which I am still climbing).
OTOH, Gradle allows you to drop into Java and do custom things easier than in Maven.