How to resolve / select a version where different platforms want different versions of a dependency

Hi,

I have the problem, that I’ve got a enforcedPlatform(..) which want liquibase-core in version 4.x and a platform (spring boot) which does bring 5.x to the table, which I don’t want (yet).

So Gradle does tell me that it does fail to select a version, however I tried different things from the docs to no avail to select the one I want:

Could not resolve org.liquibase:liquibase-core:5.0.2.
Required by:
project ‘:test’ > org.springframework.boot:spring-boot-dependencies:4.0.6
Component is the target of multiple version constraints with conflicting requirements:
4.33.0 - transitively via ‘project :base’ (runtimeElements)
5.0.2 - directly in ‘org.springframework.boot:spring-boot-dependencies:4.0.6’ (platform-runtime) (1 other path to this version)

did not help.

How can I force gradle to use the version from the enforcedPlatform (I had hopes the enforced one would be preferred to the non enforced one, but it fails nonetheless) I did create via a virtual platform:

constraints {
  implementation(enforcedPlatform("org.liquibase:liquibase-virtual-platform:$liquibaseVersion"))
  runtimeOnly(enforcedPlatform("org.liquibase:liquibase-virtual-platform:$liquibaseVersion"))
}

Is it possible to remove a dependency constraint from a platform?

Edit:

I did try:

implementation(platform(SpringBootPlugin.BOM_COORDINATES)) {
        (this as ExternalModuleDependency).exclude("org.liquibase", "liquibase-core")
}

which does help but I am not sure that is the way it should be done?

Can you share an MCVE, or maybe a build --scan URL?

Generally, enforcedPlatform is seldomly a good idea.
It is a rather heavy almost-last-resort hammer.
Better use a strict version in a normal platform.

But either way, if you have a non-strict / non-enforced version and a strict / enforced version, the strict one will win.
how the situation is exactly in your case is hard to say from this partial description.

Hm, I need to craft a small demo for that. But I tried to remove all my virtual platforms from the table and just got:

  1. a dependency (bom, via platform) I use which say strictly version 4.33.0
  2. a dependency (bom, via platform) which says 5.0.2 ( spring-boot/platform/spring-boot-dependencies/build.gradle at v4.0.6 · spring-projects/spring-boot · GitHub )

Still I get this for the dependencyInsight task:

org.liquibase:liquibase-core:4.33.0 (by constraint) FAILED
   Failures:
      - Could not resolve org.liquibase:liquibase-core:{strictly 4.33.0}.
          - Component is the target of multiple version constraints with conflicting requirements:
            4.33.0 - transitively via 'project :base' (runtimeElements)
            5.0.2 - directly in 'org.springframework.boot:spring-boot-dependencies:4.0.6' (platform-runtime)

So how can I tell / force Gradle to prefer the strictly one here?

Edit:

configurations.all {
    resolutionStrategy {
        force("org.liquibase:liquibase-core:4.33.0")
    }
}

Seems to work … fingers crossed

As I said, impossible to tell without an MCVE or at least a build --scan URL.
I tried what I understood you use and it works as expected.
So without having something concrete to look at, it is hard to say what is relevant in your setup.

I’ll provide some demo asap.

Try this one:

and:

./gradlew dependencyInsight --configuration runtimeClasspath --dependency org.liquibase:liquibase-core

Which would result in:

> Task :dependencyInsight
org.liquibase:liquibase-core:5.0.2 (by constraint) FAILED
   Failures:
      - Could not resolve org.liquibase:liquibase-core:5.0.2.
          - Cannot find a version of 'org.liquibase:liquibase-core' that satisfies the version constraints:
               Dependency path: 'root project :' (runtimeClasspath) --> 'project :sub' (runtimeElements) --> 'org.liquibase:liquibase-core:{strictly [4.0, 5.0[; prefer 4.33.0}'
               Constraint path: 'root project :' (runtimeClasspath) --> 'org.springframework.boot:spring-boot-dependencies:4.0.6' (platform-runtime) --> 'org.liquibase:liquibase-core:5.0.2'

org.liquibase:liquibase-core:5.0.2 FAILED
\--- org.springframework.boot:spring-boot-dependencies:4.0.6
     \--- runtimeClasspath

org.liquibase:liquibase-core:[4.0, 5.0[ FAILED
   Failures:
      - Could not resolve org.liquibase:liquibase-core:{strictly [4.0, 5.0[; prefer 4.33.0}. (already reported)

org.liquibase:liquibase-core:{strictly [4.0, 5.0[; prefer 4.33.0} -> [4.0, 5.0[ FAILED
\--- project :sub
     \--- runtimeClasspath

So how would you fix that / tell gradle to prefer the strictly one here?

Hm, interesting.
I’m not sure whether that is intentional or a bug.
But if you add

constraints {
    implementation(libs.liquibase)
}

to the root project, it resolves as expected.

(Besides that it does not work at all because you did not define any repositories)

Ah sorry, I have my repositories defined in my gradle setting in my home (which I always forget about), sorry for that.

About your proposal, I removed:

configurations.all {
    resolutionStrategy {
        force("org.liquibase:liquibase-core:$liquibaseVersion")
    }
}

and used:

dependencies {
    constraints {
        implementation(versionCatalog().findLibrary("liquibase").get())
    }
}

and it works now like expected.

Thanks for that suggestions, much appreciated.

So is this expected to work like this here - whom to ask? Open an issue about it (if not)?

Yeah, resolutionStrategy force is a similar heavy hammer like enforced platform.

As I said, I’m not sure whether it is expected or a bug. An issue could clarify this, yes

JFTR, I made Gradle fails to resolve a strict dependency if a platform defines another version (a non strict) for the given dep without having an extra constraint definition · Issue #37795 · gradle/gradle · GitHub to clarify, if this is expected or a bug.