Why does constraints{} add dependency to root project?

Hi everyone!
I have a simple demo Gradle multi-module project:

├── settings.gradle.kts
├── build.gradle.kts
├──greeter
│ └── build.gradle.kts
├── greeting-library
└── build.gradle.kts

root build.gradle.kts:

  subprojects {
    apply(plugin = "java")
    dependencies {
        constraints {
            "implementation"("org.apache.commons:commons-lang3:3.7")
        }
    }
}
allprojects {
    repositories {
        jcenter()
    }
}

greeting-library/build.gradle.kts

dependencies {
    implementation("org.apache.commons:commons-lang3")
}

greeter/build.gradle.kts

plugins {
    application
}

dependencies {
    implementation(project(":greeting-library"))
}

application {
    mainClassName = "greeter.Greeter"
}

I don’t understand why if I declare constraints in root build.gradle.kts and add the dependency in greeting-library the dependency also available in greeter module ?

> gradle greeter:dependencies

runtimeClasspath - Runtime classpath of source set 'main'.
+--- org.apache.commons:commons-lang3:3.7
\--- project :greeting-library
     +--- org.apache.commons:commons-lang3:3.7
     \--- org.apache.commons:commons-lang3 -> 3.7

Are there ways to declare a dependency version in the root build.gradle.kts only?

Hi @wakedeer,

I think everything is correct already.

If you look at the compileClasspath, it should look like this:

compileClasspath - ...
\--- project :greeting-library

Right?

On the runtime classpath, you have all the transitive dependencies, because you need everything to run the software. Because you have the constraints defined for all subprojects, Gradle applies a constraint everywhere once the corresponding dependency (commons-lang in the example) becomes part of the classpath. And then you see it here directly under greeter.

But it does not change the result of dependency resolution. Gradle always looks at the complete graph. It does not matter if the same constraint is there once or multiple times.

1 Like