Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Gradle - exclude a dependency for a configuration, but not for an inheriting configuration

Using Gradle 1.0 milestone 8.

My project uses slf4j+Logback for logging, so I want to prevent any transitive deps on log4j from polluting my classpath. Thus, I added a global exclusion, like so:

configurations {
    all*.exclude group: "log4j", module: "log4j"
}

However, I am using a test library (hadoop-minicluster) which has a runtime dependency on log4j, so I now need to allow a log4j dependency for my test runtime. I tried adding a direct dependency on log4j:

testRuntime group: "log4j", name: "log4j", version: "1.2.15"

and editing my exclusion code (a bit of a hack):

configurations.findAll {!it.name.endsWith('testRuntime')}.each { conf ->
    conf.exclude group: "log4j", module: "log4j"
}

But this does not work. Adding the exclusion to the testCompile conf automatically adds it to all inheriting configurations as well, including testRuntime. And it seems that this exclusion overrides even the explicit dependency that I added.

It appears that this is expected behaviour for Gradle. From the docs:

If you define an exclude for a particular configuration, the excluded transitive dependency will be filtered for all dependencies when resolving this configuration or any inheriting configuration.

So is there any other way to do what I want to achieve?

Ideas:

  • Create a new conf myTestRuntime that does not extend from testCompile, and use that for my test classpath.
    • But then I have to duplicate all dependencies for both testCompile and myTestRuntime.
  • Remove config-level exclusions. For all confs apart from testRuntime, loop through dependencies and manually remove log4j (or add a dep-level exclusion on log4j).
    • Is this even possible? Configuration.allDependencies is read-only.
like image 780
Chris B Avatar asked Mar 29 '12 03:03

Chris B


People also ask

How do you exclude a dependency from implementation of Gradle?

Option 1) per-dependency exclude rules. When you specify a dependency in your build script, you can provide an exclude rule at the same time telling Gradle not to pull in the specified transitive dependency. For example, say we have a Gradle project that depends on Google's Guava library, or more specifically com.

How do I exclude a specific version of a dependency in Maven?

Multiple transitive dependencies can be excluded by using the <exclusion> tag for each of the dependency you want to exclude and placing all these exclusion tags inside the <exclusions> tag in pom. xml. You will need to mention the group id and artifact id of the dependency you wish to exclude in the exclusion tag.

How do you resolve transitive dependencies in Gradle?

A variant of a component can have dependencies on other modules to work properly, so-called transitive dependencies. Releases of a module hosted on a repository can provide metadata to declare those transitive dependencies. By default, Gradle resolves transitive dependencies automatically.

What is compileOnly in Gradle?

compileOnly. Gradle adds the dependency to the compile classpath only (that is, it is not added to the build output). This is useful when you're creating an Android module and you need the dependency during compilation, but it's optional to have it present at runtime.


3 Answers

For now I have managed to work around the problem, but I still welcome any better solutions.

Here is what I ended up doing:

  • Add a new configuration just for log4j:

    log4j(group: 'log4j', name: 'log4j', version: '1.2.15') {
        transitive = false
    }
    
  • Leave the config-level exclusion for all configurations apart from that one:

    configurations.findAll {!it.name.endsWith('log4j')}.each { conf ->
        conf.exclude group: "log4j", module: "log4j"
    }
    
  • Add the log4j configuration to my tests' classpath:

    test {
        classpath += configurations.log4j
    }
    

This way we can get log4j.jar onto the classpath, even though it is excluded from the testRuntime configuration.

like image 194
Chris B Avatar answered Oct 13 '22 16:10

Chris B


Even i encountered similar situation where i need to exclude spark jars from including in fat jar but test cases requires spark jars to execute.so below configuration worked for me. So basically i am adding compile time dependencies to test classpath. so for your problem below solution should work

configurations{
    runtime.exclude group: 'log4j'
}

test {
        classpath += configurations.compile
}
like image 32
user3435860 Avatar answered Oct 13 '22 17:10

user3435860


You should not need to define an exclusion. Unless you reconfigured something, a project's testRuntime configuration will only be used for that project's test task.

like image 38
Peter Niederwieser Avatar answered Oct 13 '22 17:10

Peter Niederwieser