I have a multi-project layout which uses git submodules such that developers can checkout the sub projects as standalone git repos and work on them. For eg. I have Parent
gradle project which has Child1
and Child2
as sub projects.
Let me discuss the reasoning for that so that the context is laid out.
If Child1
depends on Child2
as a library, I have the Child2
dependency added in Child1
as a maven repo (implementation com.example:child2:1.0.0
) so that a developer checking out only Child1
doesn’t have broken dependencies. At the same time, I want people checking out Parent
to be able to use the Child2
dependency as a project (implementation project(:child2)
). To implement this, I use dependency substitution in Parent
only like below
allprojects {
configurations.all {
resolutionStrategy {
dependencySubstitution {
substitute module('com.example:child2') with project(':child2')
}
}
}
}
The above substitution is not working when Child1
has the spring dependency management plugin active
plugins {
id 'java'
id 'eclipse'
id 'idea'
id 'org.springframework.boot' version '2.7.5'
id 'io.spring.dependency-management' version '1.0.15.RELEASE'
}
The substitution happens as soon as the spring dependency management plugin is removed. The substitution also works if I use the substitution code in Child1
itself like
configurations.all {
resolutionStrategy {
dependencySubstitution {
substitute module('com.example:child2') with project(':child2')
}
}
}
but that’s not something that I am looking to do here.
I am able to reproduce this consistently and have created a repo with a simple reproduction (here I am replacing joda-time
with the library
project in the consumer
, both of which are present in the dep-sub-test
project, as I need an existing maven package to demonstrate`)
To reproduce:
Pull the project as is and run .\gradlew.bat :consumer:dependencies --configuration compileClasspath
to see the dependency tree. The output will have
compileClasspath - Compile classpath for source set 'main'.
+--- org.springframework.boot:spring-boot-starter-web -> 2.7.5
| +--- org.springframework.boot:spring-boot-starter:2.7.5
| ...spring stuff
\--- joda-time:joda-time:2.12.0
Comment out the lines id 'io.spring.dependency-management' version '1.0.15.RELEASE'
and implementation 'org.springframework.boot:spring-boot-starter-web'
and run the above command once again. The output will have
compileClasspath - Compile classpath for source set 'main'.
\--- joda-time:joda-time:2.12.0 -> project :library
NOTE: the org.springframework.boot:spring-boot-starter-web
dependency is only there to ensure that there is no corner case that is missed when the plugin is added but no spring dependencies are given.
The above is taken from the GitHub issue that I created. After sleeping on the issue, I have been thinking of some way that I can tell the allprojects
block in the Parent
project to apply the configurations in the block after the configuration in the child projects Child1
and Child2
are done, as to me, it seems like that the plugin is overwriting the substitution. Is there are Gradle only workaround for this?
The developer of the plugin has responded and quoting:
It would appear that Gradle loses the dependency substitution when another resolution strategy configures a version.