Shadow is an extension of the Gradle Jar task that optimizes FatJar/UberJar creation by using JarInputStream and JarOutputStream to copy file contents. This avoids the unnecessary I/O overhead of expanding jar files to disk before recombining them. Shadow provides the similar filtering, relocation, and transformation capabilities as the Maven Shade plugin. Starting with version 0.9, Shadow is a complete re-write based on core Gradle classes and concepts instead of a port of the Maven Shade code. Documentation for version 0.8 and prior can be found here.
buildscript {
repositories { jcenter() }
dependencies {
classpath 'com.github.jengelman.gradle.plugins:shadow:1.2.1'
}
}
apply plugin: 'java' // or 'groovy'. Must be explicitly applied
apply plugin: 'com.github.johnrengelman.shadow'
plugins {
id 'java' // or 'groovy' Must be explicitly applied
id 'com.github.johnrengelman.shadow' version '1.2.1'
}
Note: Applying the ShadowPlugin
to a project applies the majority of its settings via a callback on the application of
other plugins. For example, the bulk of shadow
is only added to the project if the java
or groovy
plugins are also
added. Shadow will not add them automatically, but instead listens for their application and responds.
$ gradle shadowJar //shadow the runtime configuration with project code into ./build/libs/
shadowJar
uses the same default configurations as jar
and additionally configures the classifier
to be 'all'
.
Additionally, it creates a 'shadow'
configuration and assigns the jar as an artifact of it. This configuration can
be used to add dependencies that are excluded from the shadowing.
apply plugin: 'application'
apply plugin: 'com.github.johnrengelman.shadow'
Applying both shadow
and application
to a project will create a number of additional tasks to be created. These
tasks mimic the application
plugin but execute using the output of the shadowJar
task.
Applying the application
plugin will cause the shadowJar
to include the Main-Class
attribute in the manifest of
the shadowJar
output. This is configured via the mainClassName
attribute from the application
plugin.
By default, shadowJar.manifest inherits from jar.manifest.
jar {
manifest {
attributes("Implementation-Title": "Gradle", "Implementation-Version": version)
}
}
Append to the Jar MANIFEST. Values specified here, override the values in jar.manifest.
shadowJar {
manifest {
attributes 'Test-Entry': 'PASSED'
}
}
shadowJar {
mergeServiceFiles()
}
OR
import com.github.jengelman.gradle.plugins.shadow.transformers.ServiceFileTransformer
shadowJar {
transform(ServiceFileTransformer)
}
shadowJar {
mergeServiceFiles('META-INF/griffon')
}
OR
import com.github.jengelman.gradle.plugins.shadow.transformers.ServiceFileTransformer
shadowJar {
transform(ServiceFileTransformer) {
path = 'META-INF/griffon'
}
}
shadowJar {
mergeServiceFiles {
exclude 'META-INF/services/com.acme.*'
}
}
OR
import com.github.jengelman.gradle.plugins.shadow.transformers.ServiceFileTransformer
shadowJar {
transform(ServiceFileTransformer) {
exclude 'META-INF/services/com.acme.*'
}
}
shadowJar {
mergeGroovyExtensionModules()
}
OR
import com.github.jengelman.gradle.plugins.shadow.transformers.GroovyExtensionModuleTransformer
shadowJar {
transform(GroovyExtensionModuleTransformer)
}
shadowJar {
append('NOTICE')
}
OR
import com.github.jengelman.gradle.plugins.shadow.transformers.AppendingTransformer
shadowJar {
transform(AppendingTransformer) {
resource = 'NOTICE'
}
}
shadowJar {
exclude 'LICENSE'
}
Exclude specific dependency (transitive dependencies are not excluded).
shadowJar {
dependencies {
exclude(dependency('asm:asm:3.3.1'))
}
}
Include specific dependency (transitive dependencies are not included). Note that dependency inclusion is based
on the same core classes as Gradle's CopySpec
inclusion/exclusion. By default, there is a global include, however,
declaring a specific include
effectively creates a global exclude
. That is, once an include
is made, only items
that are specifically listed for inclusion will be include in the final output.
shadowJar {
dependencies {
include(dependency('asm:asm:3.3.1'))
}
}
Include or exclude dependencies using regex pattern matching. The string is split on the :
character in the form
<group>:<name>:<version>
. Each piece is compared as a regex to the values of the resolved dependencies.
shadowJar {
dependencies {
include(dependency('asm:asm:.*'))
}
}
If a piece of the string is not specified, then that field is not used for the matching. Thus the following syntax results in the same filtering as the example above.
shadowJar {
dependencies {
include(dependency('asm:asm'))
}
}
Exclude a project dependency in a multi-project build.
shadowJar {
dependencies {
exclude(project(":myclient"))
}
}
shadowJar {
relocate 'org.objectweb.asm', 'myjarjarasm.asm'
}
shadowJar {
relocate('org.objectweb.asm', 'myjarjarasm.asm') {
exclude 'org.objectweb.asm.ClassReader'
}
}
Uses the Transformer interface.
shadowJar {
transform(<Transformer class>) {
//..configure the Transformer class instance
}
}
apply plugin: 'com.github.johnrengelman.shadow'
apply plugin: 'maven-publish'
publishing {
publications {
shadow(MavenPublication) {
from components.java
artifact shadowJar
}
}
}
apply plugin: 'com.github.johnrengelman.shadow'
apply plugin: 'maven-publish'
shadowJar {
baseName = 'myproject-all'
classifier = ''
}
publishing {
publications {
shadow(MavenPublication) {
from components.shadow
artifactId = 'myproject-all'
}
}
}
OR
apply plugin: 'com.github.johnrengelman.shadow'
apply plugin: 'maven'
shadowJar {
baseName = 'myproject-all'
classifier = ''
}
uploadShadow {
repositories {
mavenDeployer {
//configure maven deployment
}
}
}
NOTE: When using the 'maven'
plugin, the 'compile'
and 'runtime'
configurations are removed from the POM and
the 'shadow'
configuration is mapped as 'runtime'
scope. This is identical to the behavior with the
'maven-publish'
plugin
dependencies {
compile 'asm:asm:3.3.1'
compile 'org.bouncycastle:bcprov-jdk15on:1.47'
shadow 'org.bouncycastle:bcprov-jdk15on:1.47'
}
shadowJar {
dependencies {
exclude(dependency('org.bouncycastle:bcprov-jdk15on:1.47'))
}
}
This examples allows the project to compile against the BouncyCastle encryption library, but then excludes it from the shadowed jar, but including it as a dependency on the 'shadow' configuration.
Additionally, any dependencies added to the shadow
configuration will be added to the Class-Path
attribute in
the JAR Manifest for the output of shadowJar
.