From 61c75c024397857b47ff73afbe9462439d06bf90 Mon Sep 17 00:00:00 2001 From: Goooler Date: Sun, 28 Jun 2026 08:57:02 +0800 Subject: [PATCH 1/3] New addExcludedIntoShadowConfiguration --- api/shadow.api | 2 ++ .../gradle/plugins/shadow/JavaPluginsTest.kt | 27 +++++++++++++++++++ .../plugins/shadow/tasks/DependencyFilter.kt | 24 ++++++++++++++++- 3 files changed, 52 insertions(+), 1 deletion(-) diff --git a/api/shadow.api b/api/shadow.api index 3363a12af..26d403b39 100644 --- a/api/shadow.api +++ b/api/shadow.api @@ -156,6 +156,7 @@ public class com/github/jengelman/gradle/plugins/shadow/relocation/SimpleRelocat public abstract interface class com/github/jengelman/gradle/plugins/shadow/tasks/DependencyFilter : java/io/Serializable { public abstract fun dependency (Ljava/lang/Object;)Lorg/gradle/api/specs/Spec; public abstract fun exclude (Lorg/gradle/api/specs/Spec;)V + public abstract fun getAddExcludedIntoShadowConfiguration ()Lorg/gradle/api/provider/Property; public abstract fun include (Lorg/gradle/api/specs/Spec;)V public abstract fun project (Ljava/lang/Object;)Lorg/gradle/api/specs/Spec; public abstract fun resolve (Ljava/util/Collection;)Lorg/gradle/api/file/FileCollection; @@ -167,6 +168,7 @@ public abstract class com/github/jengelman/gradle/plugins/shadow/tasks/Dependenc public synthetic fun (Lorg/gradle/api/Project;Ljava/util/List;Ljava/util/List;ILkotlin/jvm/internal/DefaultConstructorMarker;)V public fun dependency (Ljava/lang/Object;)Lorg/gradle/api/specs/Spec; public fun exclude (Lorg/gradle/api/specs/Spec;)V + public fun getAddExcludedIntoShadowConfiguration ()Lorg/gradle/api/provider/Property; protected final fun getExcludeSpecs ()Ljava/util/List; protected final fun getIncludeSpecs ()Ljava/util/List; public fun include (Lorg/gradle/api/specs/Spec;)V diff --git a/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/JavaPluginsTest.kt b/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/JavaPluginsTest.kt index 7123ba48a..07897fbc1 100644 --- a/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/JavaPluginsTest.kt +++ b/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/JavaPluginsTest.kt @@ -602,6 +602,33 @@ class JavaPluginsTest : BasePluginTest() { assertThat(value).isEqualTo("junit-3.8.2.jar") } + @Issue("https://github.com/GradleUp/shadow/issues/265") + @Test + fun addExcludedDependencyIntoShadowConfiguration() { + projectScript.appendText( + """ + dependencies { + shadow 'my:a:1.0' + implementation 'my:b:1.0' + } + $shadowJarTask { + dependencies { + addExcludedIntoShadowConfiguration = true + exclude(dependency('my:b:1.0')) + } + } + """ + .trimIndent() + ) + + runWithSuccess(shadowJarPath) + + assertThat(outputShadowedJar).useAll { + containsOnly(*manifestEntries) + getMainAttr(classPathAttributeKey).isEqualTo("b-1.0.jar a-1.0.jar") + } + } + @Issue("https://github.com/GradleUp/shadow/issues/203") @ParameterizedTest @EnumSource(ZipEntryCompression::class) diff --git a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/tasks/DependencyFilter.kt b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/tasks/DependencyFilter.kt index 93291853a..43b43e5ee 100644 --- a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/tasks/DependencyFilter.kt +++ b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/tasks/DependencyFilter.kt @@ -1,5 +1,7 @@ package com.github.jengelman.gradle.plugins.shadow.tasks +import com.github.jengelman.gradle.plugins.shadow.ShadowBasePlugin.Companion.shadow +import com.github.jengelman.gradle.plugins.shadow.internal.property import java.io.Serializable import org.gradle.api.Project import org.gradle.api.artifacts.Configuration @@ -8,11 +10,22 @@ import org.gradle.api.artifacts.ProjectDependency import org.gradle.api.artifacts.ResolvedArtifact import org.gradle.api.artifacts.ResolvedDependency import org.gradle.api.file.FileCollection +import org.gradle.api.provider.Property import org.gradle.api.provider.Provider import org.gradle.api.specs.Spec +import org.gradle.api.tasks.Input // DependencyFilter is used as Gradle Input in ShadowJar, so it must be Serializable. public interface DependencyFilter : Serializable { + /** + * When `true`, excluded dependencies will be added to the `shadow` configuration. This is useful + * when you want to exclude a dependency from the shadowed JAR, but still want it to be available + * at the `Class-Path` manifest attribute. + * + * Default is `false`. + */ + @get:Input public val addExcludedIntoShadowConfiguration: Property + /** Resolve a [configuration] against the [include]/[exclude] rules in the filter. */ public fun resolve(configuration: Configuration): FileCollection @@ -39,6 +52,9 @@ public interface DependencyFilter : Serializable { @Transient protected val includeSpecs: MutableList> = mutableListOf(), @Transient protected val excludeSpecs: MutableList> = mutableListOf(), ) : DependencyFilter { + @Transient + override val addExcludedIntoShadowConfiguration: Property = + project.objects.property(false) protected abstract fun resolve( dependencies: Set, @@ -57,7 +73,13 @@ public interface DependencyFilter : Serializable { includedDependencies = includes, excludedDependencies = excludes, ) - excludes.flatMap { it.moduleArtifacts.map(ResolvedArtifact::getFile) } + val excluded = excludes.flatMap { it.moduleArtifacts.map(ResolvedArtifact::getFile) } + if (addExcludedIntoShadowConfiguration.get()) { + project.configurations.shadow.configure { shadowConfig -> + shadowConfig.plus(project.files(excluded)) + } + } + excluded } ) } From 3bd8e3c813ee0a3c484b765dc353cd70e188dede Mon Sep 17 00:00:00 2001 From: Goooler Date: Sun, 28 Jun 2026 09:54:54 +0800 Subject: [PATCH 2/3] Fix auto-adding excluded dependencies into shadow configuration --- api/shadow.api | 4 ++ .../gradle/plugins/shadow/ShadowJavaPlugin.kt | 14 +++++ .../plugins/shadow/tasks/DependencyFilter.kt | 54 ++++++++++++------- 3 files changed, 52 insertions(+), 20 deletions(-) diff --git a/api/shadow.api b/api/shadow.api index 26d403b39..209b43f29 100644 --- a/api/shadow.api +++ b/api/shadow.api @@ -161,6 +161,8 @@ public abstract interface class com/github/jengelman/gradle/plugins/shadow/tasks public abstract fun project (Ljava/lang/Object;)Lorg/gradle/api/specs/Spec; public abstract fun resolve (Ljava/util/Collection;)Lorg/gradle/api/file/FileCollection; public abstract fun resolve (Lorg/gradle/api/artifacts/Configuration;)Lorg/gradle/api/file/FileCollection; + public abstract fun resolveExcluded (Ljava/util/Collection;)Lorg/gradle/api/file/FileCollection; + public abstract fun resolveExcluded (Lorg/gradle/api/artifacts/Configuration;)Lorg/gradle/api/file/FileCollection; } public abstract class com/github/jengelman/gradle/plugins/shadow/tasks/DependencyFilter$AbstractDependencyFilter : com/github/jengelman/gradle/plugins/shadow/tasks/DependencyFilter { @@ -177,6 +179,8 @@ public abstract class com/github/jengelman/gradle/plugins/shadow/tasks/Dependenc public fun resolve (Ljava/util/Collection;)Lorg/gradle/api/file/FileCollection; protected abstract fun resolve (Ljava/util/Set;Ljava/util/Set;Ljava/util/Set;)V public fun resolve (Lorg/gradle/api/artifacts/Configuration;)Lorg/gradle/api/file/FileCollection; + public fun resolveExcluded (Ljava/util/Collection;)Lorg/gradle/api/file/FileCollection; + public fun resolveExcluded (Lorg/gradle/api/artifacts/Configuration;)Lorg/gradle/api/file/FileCollection; } public abstract class com/github/jengelman/gradle/plugins/shadow/tasks/FindResourceInClasspath : org/gradle/api/DefaultTask, org/gradle/api/tasks/util/PatternFilterable { diff --git a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/ShadowJavaPlugin.kt b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/ShadowJavaPlugin.kt index 737f7bb5c..8c24dee06 100644 --- a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/ShadowJavaPlugin.kt +++ b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/ShadowJavaPlugin.kt @@ -46,6 +46,20 @@ constructor(private val softwareComponentFactory: SoftwareComponentFactory) : Pl task.configurations.convention(provider { listOf(runtimeConfiguration) }) } artifacts.add(configurations.shadow.name, taskProvider) + + val excludedFiles = + files( + provider { + val task = taskProvider.get() + val filter = task.dependencyFilter.get() + if (filter.addExcludedIntoShadowConfiguration.getOrElse(false)) { + filter.resolveExcluded(task.configurations.get()) + } else { + files() + } + } + ) + dependencies.add(configurations.shadow.name, excludedFiles) } protected open fun Project.configureConfigurations() { diff --git a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/tasks/DependencyFilter.kt b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/tasks/DependencyFilter.kt index 43b43e5ee..46a1f9bc7 100644 --- a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/tasks/DependencyFilter.kt +++ b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/tasks/DependencyFilter.kt @@ -1,6 +1,5 @@ package com.github.jengelman.gradle.plugins.shadow.tasks -import com.github.jengelman.gradle.plugins.shadow.ShadowBasePlugin.Companion.shadow import com.github.jengelman.gradle.plugins.shadow.internal.property import java.io.Serializable import org.gradle.api.Project @@ -35,6 +34,18 @@ public interface DependencyFilter : Serializable { */ public fun resolve(configurations: Collection): FileCollection + /** + * Resolve the excluded files of a [configuration] against the [include]/[exclude] rules in the + * filter. + */ + public fun resolveExcluded(configuration: Configuration): FileCollection + + /** + * Resolve the excluded files of all [configurations] against the [include]/[exclude] rules in the + * filter and combine the results. + */ + public fun resolveExcluded(configurations: Collection): FileCollection + /** Exclude dependencies that match the provided [spec]. */ public fun exclude(spec: Spec) @@ -63,25 +74,7 @@ public interface DependencyFilter : Serializable { ) override fun resolve(configuration: Configuration): FileCollection { - return configuration - - project.files( - project.provider { - val includes = mutableSetOf() - val excludes = mutableSetOf() - resolve( - dependencies = configuration.resolvedConfiguration.firstLevelModuleDependencies, - includedDependencies = includes, - excludedDependencies = excludes, - ) - val excluded = excludes.flatMap { it.moduleArtifacts.map(ResolvedArtifact::getFile) } - if (addExcludedIntoShadowConfiguration.get()) { - project.configurations.shadow.configure { shadowConfig -> - shadowConfig.plus(project.files(excluded)) - } - } - excluded - } - ) + return configuration - resolveExcluded(configuration) } override fun resolve(configurations: Collection): FileCollection { @@ -90,6 +83,27 @@ public interface DependencyFilter : Serializable { .reduceOrNull { acc, fileCollection -> acc + fileCollection } ?: project.files() } + override fun resolveExcluded(configuration: Configuration): FileCollection { + return project.files( + project.provider { + val includes = mutableSetOf() + val excludes = mutableSetOf() + resolve( + dependencies = configuration.resolvedConfiguration.firstLevelModuleDependencies, + includedDependencies = includes, + excludedDependencies = excludes, + ) + excludes.flatMap { it.moduleArtifacts.map(ResolvedArtifact::getFile) } + } + ) + } + + override fun resolveExcluded(configurations: Collection): FileCollection { + return configurations + .map { resolveExcluded(it) } + .reduceOrNull { acc, fileCollection -> acc + fileCollection } ?: project.files() + } + override fun exclude(spec: Spec) { excludeSpecs.add(spec) } From 14a1d9341e095c24e6c38d778dff5643fa2c9ee0 Mon Sep 17 00:00:00 2001 From: Goooler Date: Sun, 28 Jun 2026 10:05:14 +0800 Subject: [PATCH 3/3] Fix lint --- .../gradle/plugins/shadow/ShadowJavaPlugin.kt | 20 ++++++++----------- 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/ShadowJavaPlugin.kt b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/ShadowJavaPlugin.kt index 8c24dee06..6dbabc76a 100644 --- a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/ShadowJavaPlugin.kt +++ b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/ShadowJavaPlugin.kt @@ -47,18 +47,14 @@ constructor(private val softwareComponentFactory: SoftwareComponentFactory) : Pl } artifacts.add(configurations.shadow.name, taskProvider) - val excludedFiles = - files( - provider { - val task = taskProvider.get() - val filter = task.dependencyFilter.get() - if (filter.addExcludedIntoShadowConfiguration.getOrElse(false)) { - filter.resolveExcluded(task.configurations.get()) - } else { - files() - } - } - ) + val excludedFiles = taskProvider.map { task -> + val filter = task.dependencyFilter.get() + if (filter.addExcludedIntoShadowConfiguration.get()) { + filter.resolveExcluded(task.configurations.get()) + } else { + files() + } + } dependencies.add(configurations.shadow.name, excludedFiles) }