Fat Jars with Excluded Dependencies in Gradle
In this post I will outline how to build a jar in Gradle that includes all project dependencies, a so-called "fat jar". However, this implementation will allow you to selectively exclude certain dependencies from the packaged jar. The motivation for this came while using Apache Storm, where any dependencies must be bundled in the jar, but the Storm libraries themselves are provided by the runtime environment and thus must not be bundled.
apply plugin: "java"
sourceCompatibility = 1.8
version = "1.0"
repositories {
mavenCentral()
maven { url "http://oss.sonatype.org/content/repositories/github-releases/" }
maven { url "http://clojars.org/repo" }
}
configurations {
provided
compile.extendsFrom provided
}
dependencies {
provided "org.apache.storm:storm-core:0.9.2-incubating"
compile "org.twitter4j:twitter4j-stream:4.0.2"
testCompile "junit:junit:4.11"
}
jar {
dependsOn configurations.runtime
from {
(configurations.runtime - configurations.provided).collect {
it.isDirectory() ? it : zipTree(it)
}
} {
exclude "META-INF/*.SF"
exclude "META-INF/*.DSA"
exclude "META-INF/*.RSA"
}
}
First we define a new configuration in line 12 called provided
. In line 13 we then make the standard compile
configuration depend on provided
. A third default configuration also exists called runtime
, which is not explicitly defined here. This extra configuration makes no difference to Gradle.
Second we define our dependencies in lines 17 and 18. Storm is defined in the provided
configuation while the Twitter API is defined in compile
, as you normally would. Remember that compile
depends on provided
, so any dependencies defined there will be available when you actually compile and run your code.
Third, in line 22-33 we build the fat jar. When running the jar
task this code instructs Gradle to include all the dependencies within the target jar file. The important bit is in line 25 where it says configurations.runtime - configurations.provided
. This takes all the runtime
dependencies minus all the provided
dependencies, leaving only dependencies explicitly defined as either compile
or runtime
.
That's it. Now you have a fat jar with some dependencies selectively excluded.