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 :

  1. Gradle 2.0
  2. JDK 1.7
  3. Logback 1.1.2

1. Project Directory

Create following project folder structure :

gradle-hello-folder

By default, Gradle is using the standard Maven project structure.

  1. ${Project}/src/main/java/
  2. ${Project}/src/main/resources/
  3. ${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.

gradle-build-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)

References

  1. Gradle : Jar Task
  2. Wikipedia : Gradle

31 comments on “Gradle – Create a Jar file with dependencies

  1. 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) }
    }
    }

    Reply
  2. Thanks guys, it solved my problems. You saved my nightmare

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

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

    task subscribe_jar(type: Jar) {
    
       baseName = 'mqttSubscriber'
    
       sourceSets.main.java.srcDirs = ['src']
        manifest {
            attributes 'Main-Class': 'mqtt.subscribe.MqttSubscriber'
    //        attributes 'Class-Path': '. ' + configurations.runtime.collect{it.name}.join(' ')
        }
    
    //    from configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }
        from { configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) } }
       with jar
    
    }
    
    Reply
    1. 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?

      Reply
  5. 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!

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

    Reply
  7. Compile configuration is deprecated for long now, kindly update:

    from { configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) } }

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

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

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

    Reply
  11. 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) }

    }
    }

    Reply
  12. After hours of google searching, you were the saving grace! Thank you so much

    Reply
  13. 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’
    }

    Reply
  14. I use the shadowjar!!!

    shadowJar {
    configurations = [project.configurations.compile]
    classifier = null
    baseName = ‘MyNewJARFileName’
    version = null
    }

    Reply
  15. Is there a way to store all the dependencies in one folder in jar, e.g. /libs ?

    Reply
  16. 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” 😉

    Reply
  17. Doesn’t work. I get “no main manifest attribute, in gradle-create-single-jar-all-1.0.jar” with the uploaded example.

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

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

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

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

      Reply

Leave a Comment

Your email address will not be published. Required fields are marked *