How to disable transitive compile dependencies

Hi,

We want to explicitly define all compile dependencies. We define the following configuration:

configurations {
    compile.transitive = false
}

We have used this configuration for sometime. We upgraded from 2.14 to 4.10.3 and just recently noticed that dependencies are being resolved transitively.

What is the correct way to force us to define all compile dependencies? We want run time to be transitive, but not compile.

This is my understanding of what changed between 2.14 and 4.10.3. Since gradle 3.4, compileClasspath was added which the Java Plugin uses. Although compileClasspath depends on compile, settings transitive = false on compile is not inherited (by design) and therefore code is compiled with a classpath that includes all the transitive dependencies.

Is this the best solution to force us to explicitly define compile dependencies?

configurations {
    compileClasspath.transitive = false
}
1 Like

Hi @A_Rhuberg,

Yes the change is correct. In Gradle 4/5/6 you have to do these things on compileClasspath (and/or runtimeClasspath). compile should not be used at all anymore. Use implementation or api to declare dependencies: https://docs.gradle.org/current/userguide/java_library_plugin.html#sec:java_library_separation

Interesting question is why you want to exclude the transitives in the first place. There might be other new Gradle features (require Gradle 6 or later Gradle 5 versions) that could be of interest for you (depending on why you do it):

  • If it is only about controlling versions, you should have a look at constraints and platforms. With Gradle 6, there are also strict versions: https://docs.gradle.org/current/userguide/platforms.html
  • If it is about controlling which things you get exactly, dependency locking could also be of interest. One of the next versions will also include dependency verification mechanisms which could be of interest here.
  • If you get ā€˜too muchā€™ dependencies transitively, you can also exclude selected dependencies or use component metadata rules to adjust wrong dependency declarations

Thanks.

We expect all components to explicitly define compile dependencies. Setting transitive = false will not allow a dependency to be satisfied because it was also required by another dependency. For example: if a component requires ā€˜com.fasterxml.jacksonā€™, it must explicitly define that dependency; it will not inherit it because it depends on another component that also depends on ā€˜com.fasterxml.jacksonā€™.

The purpose here is to make it obvious which third parties are being used.

When we upgrade, what new feature would help?

1 Like

I face exactly the same issue with the same reason: we want modules to explicitly define their dependencies. So I want to exclude for compile time transitive dependencies.

1 Like

If I understood it correctly the implementation configuration should do excaclty what you want. Replace all compile dependencies with implementation and the compile classpath will not be transitive, but the runtime classpath will be.

This behavior is however limited to dependencies you provide (your projectes or libraries). What may be unintentional is that if you depend on 3rd party libraries with maven metadata not generated by gradle, dependencies may still be transitive. This happens when the pom.xml scopes them as compile and not runtime (wich gradle does when you use implementation).

Is this your problem?

Iā€™m not the original thread author, but I feel I have the same issue. @geissld I think youā€™re right. My project uses quite a lot of 3rd party (Maven) dependencies, and some of them bring in transitive dependencies (to the same Gradle project, so this is not an issue of implementation vs. compile vs. api).

As an example, my project contains implementation 'org.apache.xmlgraphics:batik-codec', which has a transitive dependency on org.apache.xmlgraphics:xmlgraphics-commons. This is fine (and necessary?) during runtime. However, my project also requires org.apache.xmlgraphics:xmlgraphics-commons to compile. This dependency is not declared at the moment.

Iā€™d like to configure Gradle so that ā€œmissingā€ compile dependencies like the one in the example above cause an error during compilation. As a fix Iā€™d like to have an explicit implementation org.apache.xmlgraphics:xmlgraphics-commons in my code.

Iā€™m not sure if it works, but you can try to declare 3rd party dependencies as follows

dependencies {
    implementation ('group:name:version') {
        transitive = false
    }
    runtimeOnly  ('group:name:version') // hopefully adds transitive dependencies for testing

this should add the transitive dependencies at runtime, but remove them from compilation, though I havenā€™t tested this.

But be aware that you may encounter dependencies youā€™ll need to add, even though you never use them directly. Using/overwriting methods from a super classes super class that was such a case for me.

There are occasions where we intentionally exclude some dependencies. The previous examples will work (i.e. excludes any dependencies of xxxx).
runtime (xxxx) { transitive = false }