[GRADLE-3061] Exclude on direct dependency not honored if the dependency is also a transitive dependency Created: 02/Apr/14  Updated: 29/Apr/14  Resolved: 06/Apr/14

Status: Resolved
Project: Gradle
Affects Version/s: 1.11
Fix Version/s: None

Type: Bug
Reporter: Peter Niederwieser Assignee: Unassigned
Resolution: Not A Bug Votes: 1


 Description   

The SpringSource folks are seeing a problem in a number of their builds where an exclude on a direct dependency isn't honored (just) because the dependency is also a transitive dependency. Here are their instructions to reproduce (which I've verified):

1. git clone https://github.com/spring-projects/spring-data-gemfire
2. cd spring-data-gemfire
3. git checkout a2a9707f0254a7acba41321484992e1343f632cc
4. ./gradlew dependencies

In the output you should see commons-logging listed beneath spring-core. For example:

compile - Compile classpath for source set 'main'.
+--- org.slf4j:slf4j-api:1.6.4 -> 1.7.6
+--- org.slf4j:jcl-over-slf4j:1.6.4 -> 1.7.6

--- org.slf4j:slf4j-api:1.7.6
+--- org.springframework:spring-core:3.2.8.RELEASE
--- commons-logging:commons-logging:1.1.3

If you look in build.gradle, it should be excluded:

compile("org.springframework:spring-core:$springVersion")

{ exclude module: "commons-logging" }

Using a configuration-wide or project-wide exclude solves this problem, but they'd rather not do this, one reason being that this will result in lots of bogus excludes in the generated POM.

Related support ticket: 1418



 Comments   
Comment by Adam Murdoch [ 06/Apr/14 ]

This is the intended behaviour. Each dependency edge is treated independently, and a module is included if there is a path to the module that does not exclude it.

Comment by Andy Wilkinson [ 07/Apr/14 ]

I understand that this is the intended behaviour, but I'm surprised that you apparently don't think that it could be improved. One of Gradle's benefits is the reduced verbosity of our build scripts but to work around this behaviour we'd have to repeat the exclude for every dependency with a transitive dependency on spring-core. For example:

compile("org.springframework:spring-tx:4.0.3.RELEASE") {
        exclude group: "commons-logging", module: "commons-logging"
compile("org.springframework:spring-core:4.0.3.RELEASE") {
        exclude group: "commons-logging", module: "commons-logging"
}

The unwanted side-effect of this is that the generated POM files now contain superfluous exclusions. An alternative that Peter suggested was to use configuration-wide or even project-wide exclusions. While it addresses the verbosity of the build script by removing the repetition of the exclude, it makes the problem of the superfluous exclusions even worse. We could, as Peter has suggested, post-process the generated POMs somehow, but then we're back repeating ourselves as the knowledge of the need to exclude commons logging would be duplicated and spread across multiple places in our build.

I'd love to see an improvement to Gradle so that exclusions can be declared in a DRY manner and without having to resort to post-processing to also have concise generated pom files.

Comment by Adam Murdoch [ 18/Apr/14 ]

Andy Wilkinson, we're unlikely to change this behaviour, but we can certainly do things so you end up with a concise build and a reasonable looking pom.

Why is it that you want to exclude commons-logging?

Comment by Andy Wilkinson [ 20/Apr/14 ]

Typically we exclude commons-logging as a project has elected to use SLF4J instead. In that scenario we exclude commons-logging and depend on jcl-over-slf4j

Comment by Adam Murdoch [ 28/Apr/14 ]

Ok. The idea is that you would use a dependency resolve rule instead to substitute all usages of commons-logging with jcl-over-slf4j. Does this not work for you?

Comment by Andy Wilkinson [ 29/Apr/14 ]

It somewhat works for the commons-logging case. We'd need to keep the exclude on the spring-core dependency declaration as we need the exclusion to be included in the generated pom. I say somewhat, as I'm not keen on having to duplicate the don't-use-commons-logging logic.

We also have numerous cases where we just want to exclude a dependency entirely, for example a JAXB 2.0 dependency that is redundant as it's included in JDK 6 and later. Do you have a suggestion for this scenario? It doesn't look like a dependency resolve rule can be used to exclude a dependency.

Generated at Wed Jun 30 12:38:51 CDT 2021 using Jira 8.4.2#804003-sha1:d21414fc212e3af190e92c2d2ac41299b89402cf.