Creating self-contained, executable Jars with Gradle and Shadow

Describes how to use Gradle and its Shadow plugin to create a self contained, executable Jar. No more classpath management..

Object Partners

Earlier this year, we started implementing a new backend REST architecture for our application based on Yammer/Coda Hale’s Dropwizard Framework. Since we don’t use Maven anywhere in our stack, we decided to use Gradle as our build tool. This gives us enormous flexibility as we built our new backend around the concept of “micro-services” - each service is isolated from the others and responsible for a specific piece of functionality.

Since these services aren’t WARs, we wanted a way to deploy a pre-packaged jar that we could simply execute on our servers. Maven has a nice tool for this - Apache Maven Shade Plugin. It repackages all of your application’s dependencies into a single JAR file and offers a variety of extension points for effecting the contents of the resulting file. Unfortunately, at the time, Gradle lacked a similar plugin (there are a variety of similar plugins but all had severe limitations for our application). Instead, we wrote a Gradle port of the Shade plugin - Gradle Shadow Plugin.

Shadow is a port of the Shade plugin including most of its extensions points. This makes it easier for converting existing Maven builds to Gradle. It is open sourced under the ALv2 and contributions are most welcome.

To Shadow enable your project, add the BinTray repository and the Shadow plugin dependency to your buildscript configuration like so:

apply plugin: 'groovy'
apply plugin: 'shadow'

buildscript {
    repositories {
        maven {
            name 'Shadow'
            url 'http://dl.bintray.com/content/johnrengelman/gradle-plugins'
        }
    }
    dependencies {
        classpath 'org.gradle.plugins:shadow:0.7.4'
    }
}

repositories {
    mavenCentral()
}

dependencies {
    compile 'org.codehaus.groovy:groovy-all:2.1.5'
}

version = '0.1'
jar {
    manifest {
        attributes 'Main-Class': 'blog.shadow.HelloWorld'
    }
}

By default, Shadow will bundle all our your compile and runtime dependencies into an additional JAR with the classifier ‘shadow’ appended to it. This JAR is directly executable by executing the JAR:

$ java -jar build/libs/shadow-blog-0.1-shadow.jar
 Hello World

Notice that trying to execute the output of the normal JAR tasks results in an error due to the Groovy library not being available on the classpath:

$ java -jar build/libs/shadow-blog-0.1.jar
Exception in thread "main" java.lang.NoClassDefFoundError: groovy/lang/GroovyObject at
java.lang.ClassLoader.defineClass1(Native Method) at
java.lang.ClassLoader.defineClassCond(ClassLoader.java:631) at
java.lang.ClassLoader.defineClass(ClassLoader.java:615) at
java.security.SecureClassLoader.defineClass(SecureClassLoader.java:141) at
java.net.URLClassLoader.defineClass(URLClassLoader.java:283) at
java.net.URLClassLoader.access$000(URLClassLoader.java:58) at
java.net.URLClassLoader$1.run(URLClassLoader.java:197) at
java.security.AccessController.doPrivileged(Native Method) at
java.net.URLClassLoader.findClass(URLClassLoader.java:190) at
java.lang.ClassLoader.loadClass(ClassLoader.java:306) at
sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301) at
java.lang.ClassLoader.loadClass(ClassLoader.java:247)
Caused by: java.lang.ClassNotFoundException: groovy.lang.GroovyObject at
java.net.URLClassLoader$1.run(URLClassLoader.java:202) at
java.security.AccessController.doPrivileged(Native Method) at
java.net.URLClassLoader.findClass(URLClassLoader.java:190) at
java.lang.ClassLoader.loadClass(ClassLoader.java:306) at
sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301) at
java.lang.ClassLoader.loadClass(ClassLoader.java:247)
... 12 more

This simple example can be found on Github - Shadow Blog. For more advanced usages of the Shadow plugin, refer to the README

Share this Post

Related Blog Posts

JVM

Custom Authentication with the Grails Spring Security Core Plugin

July 11th, 2013

A tutorial with backing github project detailing how to build custom authentication solutions with the Grails Spring Security Core plugin.

Object Partners
JVM

Configuring Quartz 2 with Spring in clustered mode

July 9th, 2013

Run Quartz jobs to fire only once per cluster, not once per server, while still providing beans from the Spring managed context and using the latest version of Quartz.

Jeff Sheets
JVM

Getting Groovy with Spring and WebSockets

June 25th, 2013

A demonstration of leveraging Project Tyrus with Groovy and Spring to build a WebSocket-driven application.

Object Partners

About the author