The Shadow Knows Gradle

Someone recently complained on Twitter that the so-called Shadow plugin for Gradle, written by the inestimable John Engleman, no longer worked on Gradle 2.11 or 2.12. Commenters were quick to point out that the latest version (1.2.3) of the plugin did work. I thought I’d put together this quick blog post to demonstrate that it works fine.

As a overview, the Shadow plugin creates what’s called a “fat” jar, including all the dependencies, so you can deliver a runnable final product without installing anything other than Java.

I made a trivial Java library project using the Gradle Init plugin, using Spock testing (because I couldn’t help using Spock). Fortunately, this time I remembered to create a folder to hold it in ahead of time.

> md temp/shadow_demo
> cd temp/shadow_demo
> gradle init –type java-library –test-framework spock

That created a typical Java project, with folders src/main/java and src/test/groovy in it, along with a source class called and a test called LibraryTest.groovy.

(First minor complaint: the test case should be called LibrarySpec.groovy. The compiler doesn’t require you to end your Spock tests with the word Spec, but it’s a standard idiom by now. Plus, it helps me keep straight which of my tests are Spock tests and which are JUnit tests.)

I then opened the build.gradle file in the root of the project in order to add the shadow plugin. Here’s how it looked when I started:

[sourcecode language=”groovy”]
* This build file was auto generated by running the Gradle ‘init’ task
* by ‘kousen’ at ‘3/14/16 5:20 PM’ with Gradle 2.12
* This generated file contains a sample Java project to get you started.
* For more details take a look at the Java Quickstart chapter in the Gradle
* user guide available at

// Apply the java plugin to add support for Java
apply plugin: ‘java’

// Apply the groovy plugin to also add support for Groovy (needed for Spock)
apply plugin: ‘groovy’

// In this section you declare where to find the dependencies of your project
repositories {
// Use ‘jcenter’ for resolving your dependencies.
// You can declare any Maven/Ivy/file repository here.

// In this section you declare the dependencies for your production and test code
dependencies {
// The production code uses the SLF4J logging API at compile time
compile ‘org.slf4j:slf4j-api:1.7.18’

// We use the latest groovy 2.x version for Spock testing
compile ‘org.codehaus.groovy:groovy-all:2.4.6’

// Use the awesome Spock testing and specification framework even with Java
testCompile ‘org.spockframework:spock-core:1.0-groovy-2.4’
testCompile ‘junit:junit:4.12’

(Second minor complaint: the build file adds both the java and groovy plugins. That’s redundant. The groovy plugin already includes all the needed java functionality.

I removed the comments and cleaned up the build file a bit, adding the shadow plugin.

[sourcecode language=”groovy”]
plugins {
id ‘groovy’
id ‘com.github.johnrengelman.shadow’ version ‘1.2.3’

repositories {

dependencies {
compile ‘org.slf4j:slf4j-api:1.7.18’

compile ‘org.codehaus.groovy:groovy-all:2.4.6’

testCompile ‘org.spockframework:spock-core:1.0-groovy-2.4’
testCompile ‘junit:junit:4.12’

I’m using the newer plugins block syntax instead of the conventional `buildscript` approach. The page at the Gradle plugins site for the Shadow plugin ( shows the details. Note that the section at the bottom of that page labelled “About the new plugin mechanism…” gives additional details on the newer approach.

If you run the gradle tasks command at this point, you’ll see a lot of output, some of which is relevant for this demo.

[sourcecode language=”groovy”]
> gradle tasks

All tasks runnable from root project

Build tasks
assemble – Assembles the outputs of this project.
build – Assembles and tests this project.
buildDependents – Assembles and tests this project and all projects that depend on it.
buildNeeded – Assembles and tests this project and all projects it depends on.
classes – Assembles main classes.
clean – Deletes the build directory.
jar – Assembles a jar archive containing the main classes.
testClasses – Assembles test classes.

Build Setup tasks
init – Initializes a new Gradle build. [incubating]
wrapper – Generates Gradle wrapper files. [incubating]

Documentation tasks
groovydoc – Generates Groovydoc API documentation for the main source code.
javadoc – Generates Javadoc API documentation for the main source code.

Help tasks
buildEnvironment – Displays all buildscript dependencies declared in root project ‘shadow_demo’.
components – Displays the components produced by root project ‘shadow_demo’. [incubating]
dependencies – Displays all dependencies declared in root project ‘shadow_demo’.
dependencyInsight – Displays the insight into a specific dependency in root project ‘shadow_demo’.
help – Displays a help message.
model – Displays the configuration model of root project ‘shadow_demo’. [incubating]
projects – Displays the sub-projects of root project ‘shadow_demo’.
properties – Displays the properties of root project ‘shadow_demo’.
tasks – Displays the tasks runnable from root project ‘shadow_demo’.

Shadow tasks
knows – Do you know who knows?
shadowJar – Create a combined JAR of project and runtime dependencies

Verification tasks
check – Runs all checks.
test – Runs the unit tests.

Pattern: clean<TaskName>: Cleans the output files of a task.
Pattern: build<ConfigurationName>: Assembles the artifacts of a configuration.
Pattern: upload<ConfigurationName>: Assembles and uploads the artifacts belonging to a configuration.

To see all tasks and more detail, run gradle tasks –all

To see more detail about a task, run gradle help –task <task>


Total time: 9.466 secs

Note the existence of the shadowJar task, which creates the fat jar.

My trivial app doesn’t have a Java class with a main method in it, however, so creating a shadow jar wouldn’t actually accomplish much. Therefore, after renaming src/main/java to src/main/groovy, I added a tiny groovy script called src/main/groovy/demo.groovy:

[sourcecode language=”groovy”]
println ‘What up, World?’

Then I added the application plugin to the Gradle build and set the main class to my script, giving me the final form of the build file:

[sourcecode language=”groovy”]
plugins {
id ‘groovy’
id ‘application’
id ‘com.github.johnrengelman.shadow’ version ‘1.2.3’

mainClassName = ‘demo’

repositories {

dependencies {
compile ‘org.slf4j:slf4j-api:1.7.18’
compile ‘org.codehaus.groovy:groovy-all:2.4.6’

testCompile ‘org.spockframework:spock-core:1.0-groovy-2.4’
testCompile ‘junit:junit:4.12’

The (built in) application plugin adds the run and shadowRun tasks to Gradle. Executing those is easy enough, too:

> gradle run
:compileJava UP-TO-DATE
:processResources UP-TO-DATE
What up, World?


Total time: 2.688 secs

> gradle runShadow
:compileJava UP-TO-DATE
:compileGroovy UP-TO-DATE
:processResources UP-TO-DATE
:classes UP-TO-DATE
What up, World?


Total time: 2.503 secs

The first runs the app without the shadow jar, and the second uses it. Everything looks good. The GitHub page for the shadow plugin describes lots of ways to customize it, but I didn’t need any of that for my demo.

Of course, there’s no way you can talk about the shadow plugin without running the additional task it adds, namely knows:

> gradle knows

No, The Shadow Knows….



Total time: 1.043 secs

That, of course, is worth the whole demo. 🙂

5 responses to “The Shadow Knows Gradle”

  1. Of all the places i searched for an answer to my problem, I was shown the light here. The blog was very informative. Thank you so much sir.


    where is the Def of task “shadowJar” here ?

  3. I find for a simple groovy script I have to include src.main.groovy into the mainClassName, the compiled classes aren’t copied into the root. strange

  4. This article was very helpful towards building an executable JAR from a single Groovy script that I had. When I did execute the JAR using ‘java -jar …’ I got no main manifest attribute, how do I set the shadow plugin to include that attribute?

  5. Amazing, this is a great article! I did enjoyed reading it, keep your post .

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.