Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Which Maven BOM determines a dependency's version in Gradle 5?

I am currently developing a Gradle 5 project that imports two different Maven BOMs. Therefore, I use the native Gradle syntax without the dependency management plugin. However, both BOMs may define different versions for the same dependency.

dependencies {
    implementation platform ("org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}")
    implementation platform ("com.organisation:xyz:${otherBomVersion}")
}

As far as I know in Maven the first BOM which defines a version for a given dependency determines it. In contrast, in the Gradle dependency management plugin the last BOM which defines a version for a given dependency determines it.

How is the order of imported BOMs handled in pure Gradle 5?

like image 315
Robin Ellerkmann Avatar asked Oct 17 '22 06:10

Robin Ellerkmann


2 Answers

The order of BOMs, or wherever the dependency is declared, doesn't matter at all in Gradle. Unlike Maven, which uses a nearest first approach, Gradle takes all dependency information in consideration and selects the highest. The documentation states

Gradle will consider all requested versions, wherever they appear in the dependency graph. Out of these versions, it will select the highest one.

A practical example. The following declaration will always select 2.2.5.RELEASE of Spring Cloud Gateway defined by spring-cloud-dependencies BOM version Hoxton.SR8 no matter which platform() declaration is listed first:

dependencies {
    implementation platform('org.springframework.cloud:spring-cloud-dependencies:Hoxton.SR8')
    implementation platform('org.springframework.cloud:spring-cloud-dependencies:Greenwich.SR6')
    
    implementation 'org.springframework.cloud:spring-cloud-starter-gateway'
}

The dependency insight report may look like this:

> gradlew -q dependencyInsight --dependency spring-cloud-starter-gateway
org.springframework.cloud:spring-cloud-starter-gateway:2.2.5.RELEASE (by constraint)
   variant "compile" [
      org.gradle.status              = release (not requested)
      org.gradle.usage               = java-api
      org.gradle.libraryelements     = jar (compatible with: classes)
      org.gradle.category            = library (not requested)

      Requested attributes not found in the selected variant:
         org.gradle.dependency.bundling = external
         org.gradle.jvm.version         = 8
   ]

org.springframework.cloud:spring-cloud-starter-gateway:2.2.5.RELEASE
\--- org.springframework.cloud:spring-cloud-dependencies:Hoxton.SR8
     \--- compileClasspath

org.springframework.cloud:spring-cloud-starter-gateway -> 2.2.5.RELEASE
\--- compileClasspath

You may use enforcedPlatform() should you prefer versions from a specific BOM.

like image 161
thokuest Avatar answered Oct 19 '22 00:10

thokuest


A simpler suggestion would be to use this mechanism described in the Spring Boot Gradle Plugin docs, whereby you can explicitly override versions picked by setting properties.

The example they give:

ext['slf4j.version'] = '1.7.20'

The full list of properties you can set can be found in the Spring Boot reference documentation.

In the end you would have an explicit way to override the defaults given by Spring Boot.

Ah, and now I see you are in fact not using that plugin, so this mechanism doesn't apply to you. Well, if you start using it, the above should work as intended and be predictable.

like image 45
rud Avatar answered Oct 19 '22 02:10

rud