# Configuring Shadowed Dependencies

Shadow configures the default [`ShadowJar`][ShadowJar] task to merge all dependencies from the project's
`runtimeClasspath` configuration into the final JAR. The configurations from which to source dependencies for the
merging can be configured using the [`configurations`][ShadowJar.configurations] property of the
[`ShadowJar`][ShadowJar] task type.

=== "Kotlin"

    ```kotlin
    tasks.shadowJar {
      configurations = project.configurations.compileClasspath.map { listOf(it) }
    }
    ```

=== "Groovy"

    ```groovy
    tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) {
      configurations = project.configurations.named('compileClasspath').map { [it] }
    }
    ```

The above code sample would configure the [`ShadowJar`][ShadowJar] task to merge dependencies from only the
`compileClasspath` configuration.
This means any dependency declared in the `runtimeOnly` configuration would be **not** be included in the final JAR.

> Note the literal use of [`project.configurations`][Project.configurations] when setting the
> [`configurations`][ShadowJar.configurations] attribute of a [`ShadowJar`][ShadowJar] task.
> This is **required**. It may be tempting to specify `configurations = [configurations.compileClasspath]` but this will
> not have the intended effect, as `configurations.compile` will try to delegate to the
> [`configurations`][ShadowJar.configurations] property of the [`ShadowJar`][ShadowJar] task instead of the `project`

## Embedding Local Jar Files into Your Shadowed JAR

The [`ShadowJar`][ShadowJar] task is a subclass of the [`Jar`][Jar] task, which means that the [`Jar.from`][Jar.from]
method can be used to add extra files.

=== "Kotlin"

    ```kotlin
    dependencies {
      // Merge foo.jar (with unzipping) into the shadowed JAR.
      implementation(files("foo.jar"))
    }

    tasks.shadowJar {
      from("bar.jar") {
        // Copy bar.jar file (without unzipping) into META-INF/ in the shadowed JAR.
        into("META-INF")
      }
    }
    ```

=== "Groovy"

    ```groovy
    dependencies {
      // Merge foo.jar (with unzipping) into the shadowed JAR.
      implementation files('foo.jar')
    }

    tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) {
      from('bar.jar') {
        // Copy bar.jar file (without unzipping) into META-INF/ in the shadowed JAR.
        into('META-INF')
      }
    }
    ```

Someone may need the unzipped `bar.jar` to be bundled, try out [`zipTree`][Project.zipTree]

=== "Kotlin"

    ```kotlin
    tasks.shadowJar {
      from(zipTree("bar.jar")) {
        // Copy unzipped bar.jar files into META-INF/ in the shadowed JAR.
        into("META-INF")
      }
    }
    ```

=== "Groovy"

    ```groovy
    tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) {
      from(zipTree('bar.jar')) {
        // Copy unzipped bar.jar files into META-INF/ in the shadowed JAR.
        into('META-INF')
      }
    }
    ```

See also [Adding Extra Files](../README.md#adding-extra-files)

## Embedding Non-JAR Dependencies into Your Shadowed JAR

Dependencies added into `runtimeClasspath` configuration (`api`, `implementation`, `runtimeOnly`) will be unzipped and
merged into the shadowed JAR. Not all dependencies are JAR files, e.g. some of them are
[POM files](https://repo1.maven.org/maven2/org/graalvm/polyglot/js-community/24.2.2/),
[SO files](https://repo1.maven.org/maven2/io/github/ganadist/sqlite4java/libsqlite4java-osx-aarch64/1.0.392/),
and so on. If such dependencies are added into `runtimeClasspath`, you will encounter the following error when building
the shadowed JAR:

```
* What went wrong:
Execution failed for task ':shadowJar'.
> Cannot expand ZIP '/home/user/.gradle/caches/modules-2/files-2.1/some/of/non/jar/file.pom'.
...
Caused by: java.util.zip.ZipException: Archive is not a ZIP archive
  at org.apache.commons.compress.archivers.zip.ZipFile.positionAtEndOfCentralDirectoryRecord(ZipFile.java:562)
  at org.apache.commons.compress.archivers.zip.ZipFile.openZipChannel(ZipFile.java:504)
  at org.apache.commons.compress.archivers.zip.ZipFile.access$000(ZipFile.java:88)
  at org.apache.commons.compress.archivers.zip.ZipFile$Builder.get(ZipFile.java:159)
  at org.gradle.api.internal.file.archive.ZipFileTree.lambda$visit$0(ZipFileTree.java:97)
  ... 146 more
```

To embed such dependencies into your shadowed JAR, you can use the [`Jar.from`][Jar.from] method with a custom
configuration.

=== "Kotlin"

    ```kotlin
    val nonJar = configurations.create("nonJar")

    // This is necessary to make the dependencies in `nonJar` available at compile time.
    // If you don't need that, you can skip this step.
    configurations.named("compileClasspath") {
      extendsFrom(nonJar)
    }

    dependencies {
      nonJar("org.graalvm.js:js-community:24.2.2")
      nonJar("io.github.ganadist.sqlite4java:libsqlite4java-osx-aarch64:1.0.392")
      // If you add a real JAR file into the new `nonJar` configuration, it will be included as-is. Different from `implementation`.
      nonJar(files("foo.jar"))
    }

    tasks.shadowJar {
      from(nonJar)
    }
    ```

=== "Groovy"

    ```groovy
    def nonJar = configurations.create('nonJar')

    // This is necessary to make the dependencies in `nonJar` available at compile time.
    // If you don't need that, you can skip this step.
    configurations.compileClasspath {
      extendsFrom nonJar
    }

    dependencies {
      add('nonJar', 'org.graalvm.js:js-community:24.2.2')
      add('nonJar', 'io.github.ganadist.sqlite4java:libsqlite4java-osx-aarch64:1.0.392')
      // If you add a real JAR file into the new `nonJar` configuration, it will be included as-is. Different from `implementation`.
      add('nonJar', files('foo.jar'))
    }

    tasks.shadowJar {
      from(nonJar)
    }
    ```

### Excluding Non-JAR Transitive Dependencies

If the non-JAR file is a transitive dependency (e.g., a POM-only metapackage) that you don't actually need
in your shadowed JAR, you can exclude it using the `dependencies` block instead of embedding it.

=== "Kotlin"

    ```kotlin
    tasks.shadowJar {
      dependencies {
        exclude(
          // Exclude the transitive dependency on js-community, which can't be unzipped by the task.
          dependency("org.graalvm.js:js-community:.*"),
        )
      }
    }
    ```

=== "Groovy"

    ```groovy
    tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) {
      dependencies {
        exclude(
          // Exclude the transitive dependency on js-community, which can't be unzipped by the task.
          dependency('org.graalvm.js:js-community:.*'),
        )
      }
    }
    ```

## Filtering Dependencies

Individual dependencies can be filtered from the final JAR by using the `dependencies` block of a
[`ShadowJar`][ShadowJar] task. Dependency filtering does **not** apply to transitive dependencies.
That is, excluding a dependency does not exclude any of its dependencies from the final JAR.

The `dependency` blocks provides a number of methods for resolving dependencies using the notations familiar from
Gradle's [`project.configurations`][Project.configurations] block.

=== "Kotlin"

    ```kotlin
    dependencies {
      implementation("org.apache.logging.log4j:log4j-core:2.11.1")
    }

    tasks.shadowJar {
      dependencies {
        exclude(dependency("org.apache.logging.log4j:log4j-core:2.11.1"))
      }
    }
    ```

=== "Groovy"

    ```groovy
    dependencies {
      implementation 'org.apache.logging.log4j:log4j-core:2.11.1'
    }

    tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) {
      dependencies {
        exclude(dependency('org.apache.logging.log4j:log4j-core:2.11.1'))
      }
    }
    ```

=== "Kotlin"

    ```kotlin
    dependencies {
      implementation(project(":api"))
    }

    tasks.shadowJar {
      dependencies {
        exclude(dependency(":api"))
      }
    }
    ```

=== "Groovy"

    ```groovy
    dependencies {
      implementation project(':api')
    }

    tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) {
      dependencies {
        exclude(project(':api'))
      }
    }
    ```

> While not being able to filter entire transitive dependency graphs might seem like an oversight, it is necessary
> because it would not be possible to intelligently determine the build author's intended results when there is a
> common dependency between two 1st level dependencies when one is excluded and the other is not.

### Using Regex Patterns to Filter Dependencies

Dependencies can be filtered using regex patterns.
Coupled with the `<group>:<artifact>:<version>` notation for dependencies, this allows for excluding/including
using any of these individual fields.

=== "Kotlin"

    ```kotlin
    dependencies {
      implementation("org.apache.logging.log4j:log4j-core:2.11.1")
    }

    tasks.shadowJar {
      dependencies {
        exclude(dependency("org.apache.logging.log4j:log4j-core:.*"))
      }
    }
    ```

=== "Groovy"

    ```groovy
    dependencies {
      implementation 'org.apache.logging.log4j:log4j-core:2.11.1'
    }

    tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) {
      dependencies {
        exclude(dependency('org.apache.logging.log4j:log4j-core:.*'))
      }
    }
    ```

Any of the individual fields can be safely absent and will function as though a wildcard was specified.

=== "Kotlin"

    ```kotlin
    dependencies {
      implementation("org.apache.logging.log4j:log4j-core:2.11.1")
    }

    tasks.shadowJar {
      dependencies {
        exclude(dependency(":org.apache.logging.log4j:log4j-core"))
      }
    }
    ```

=== "Groovy"

    ```groovy
    dependencies {
      implementation 'org.apache.logging.log4j:log4j-core:2.11.1'
    }

    tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) {
      dependencies {
        exclude(dependency('org.apache.logging.log4j:log4j-core'))
      }
    }
    ```

The above code snippet is functionally equivalent to the previous example.

This same pattern can be used for any of the dependency notation fields. e.g.

- `org.apache.logging.log4j:.*`
- `org.apache.logging.log4j:log4j.*`
- `org.apache.logging.log4j:log4j-core:.*`
- `org.apache.logging.*:log4j-core:.*`
- `.*:log4j-core:.*`
- ...

=== "Kotlin"

    ```kotlin
    dependencies {
      implementation("org.apache.logging.log4j:log4j-core:2.11.1")
    }

    tasks.shadowJar {
      dependencies {
        exclude(dependency(":log4j-core:2.11.1"))
      }
    }
    ```

=== "Groovy"

    ```groovy
    dependencies {
      implementation 'org.apache.logging.log4j:log4j-core:2.11.1'
    }

    tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) {
      dependencies {
        exclude(dependency(':log4j-core:2.11.1'))
      }
    }
    ```

=== "Kotlin"

    ```kotlin
    dependencies {
      implementation("org.apache.logging.log4j:log4j-core:2.11.1")
    }

    tasks.shadowJar {
      dependencies {
        exclude(dependency("org.apache.logging.log4j:2.11.1"))
      }
    }
    ```

=== "Groovy"

    ```groovy
    dependencies {
      implementation 'org.apache.logging.log4j:log4j-core:2.11.1'
    }

    tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) {
      dependencies {
        exclude(dependency('org.apache.logging.log4j:2.11.1'))
      }
    }
    ```

### Using type-safe dependency accessors

You can also use type-safe project accessors or version catalog accessors to filter dependencies.

=== "Kotlin"

    ```kotlin
    dependencies {
      // Have to declare this dependency in your libs.versions.toml
      implementation(libs.log4j.core)
      // Have to enable `TYPESAFE_PROJECT_ACCESSORS` flag in your settings.gradle.kts
      implementation(projects.api)
    }

    tasks.shadowJar {
      dependencies {
        exclude(dependency(libs.log4j.core))
        exclude(project(projects.api))
      }
    }
    ```

=== "Groovy"

    ```groovy
    dependencies {
      // Have to declare this dependency in your libs.versions.toml
      implementation libs.log4j.core
      // Have to enable `TYPESAFE_PROJECT_ACCESSORS` flag in your settings.gradle
      implementation projects.api
    }

    tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) {
      dependencies {
        exclude(dependency(libs.log4j.core))
        exclude(project(projects.api))
      }
    }
    ```

### Programmatically Selecting Dependencies to Filter

If more complex decisions are needed to select the dependencies to be included, the
[`ShadowJar.dependencies`][ShadowJar.dependencies]
block provides a method that accepts a `Closure` for selecting dependencies.

=== "Kotlin"

    ```kotlin
    dependencies {
      implementation("org.apache.logging.log4j:log4j-core:2.11.1")
    }

    tasks.shadowJar {
      dependencies {
        exclude {
          it.moduleGroup == "org.apache.logging.log4j"
        }
      }
    }
    ```

=== "Groovy"

    ```groovy
    dependencies {
      implementation 'org.apache.logging.log4j:log4j-core:2.11.1'
    }

    tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) {
      dependencies {
        exclude {
          it.moduleGroup == 'org.apache.logging.log4j'
        }
      }
    }
    ```



[Jar.from]: https://docs.gradle.org/current/dsl/org.gradle.jvm.tasks.Jar.html#org.gradle.jvm.tasks.Jar:from(java.lang.Object,%20org.gradle.api.Action)
[Jar]: https://docs.gradle.org/current/dsl/org.gradle.api.tasks.bundling.Jar.html
[ShadowJar.configurations]: ../../api/shadow/com.github.jengelman.gradle.plugins.shadow.tasks/-shadow-jar/configurations.html
[ShadowJar.dependencies]: ../../api/shadow/com.github.jengelman.gradle.plugins.shadow.tasks/-shadow-jar/dependencies.html
[ShadowJar]: ../../api/shadow/com.github.jengelman.gradle.plugins.shadow.tasks/-shadow-jar/index.html
[Project.configurations]: https://docs.gradle.org/current/dsl/org.gradle.api.Project.html#org.gradle.api.Project:configurations
[Project.zipTree]: https://docs.gradle.org/current/dsl/org.gradle.api.Project.html#org.gradle.api.Project:zipTree(java.lang.Object)
