Declaring Rich Versions
Gradle supports a rich model for declaring versions, which allows you to combine different levels of version information.
The terms and their meaning are explained below, from the strongest to the weakest:
strictly
-
Any version not matched by this version notation will be excluded. This is the strongest version declaration. On a declared dependency, a
strictly
can downgrade a version. For a transitive dependency, dependency resolution will fail if no acceptable version can be selected. See overriding dependency version for details. This term supports dynamic versions.When defined, this overrides any previous
require
declaration and clears previousreject
.
require
-
Implies that the selected version cannot be lower than what
require
accepts but could be higher through conflict resolution, even if higher has an exclusive higher bound. This is what a direct dependency translates to. This term supports dynamic versions.When defined, this overrides any previous
strictly
declaration and clears previousreject
.
prefer
-
This is a very soft version declaration. It applies only if there is no stronger non-dynamic opinion on a version of the module. This term does not support dynamic versions.
Definition can complement
strictly
orrequire
.When defined, this overrides any previous
prefer
declaration and clears previousreject
.
There is also an additional term outside of the level hierarchy:
reject
-
Declares that specific version(s) are not accepted for the module. This will cause dependency resolution to fail if the selected version is rejected. This term supports dynamic versions.
The following table illustrates several use cases and how to combine the different terms for rich version declaration:
Which version(s) of this dependency are acceptable? | strictly |
require |
prefer |
rejects |
Selection result |
---|---|---|---|---|---|
Tested with version |
1.5 |
Any version starting from |
|||
Tested with |
[1.0, 2.0[ |
1.5 |
Any version between |
||
Tested with |
[1.0, 2.0[ |
1.5 |
Any version between |
||
Same as above, with |
[1.0, 2.0[ |
1.5 |
1.4 |
Any version between |
|
No opinion, works with |
1.5 |
|
|||
No opinion, prefer the latest release. |
|
The latest release at build time. |
|||
On the edge, latest release, no downgrade. |
|
The latest release at build time. |
|||
No other version than 1.5. |
1.5 |
1.5, or failure if another |
|||
|
[1.5,1.6[ |
Latest |
Lines annotated with a lock (π) indicate that leveraging dependency locking makes sense in this context. Another concept related to rich version declaration is the ability to publish resolved versions instead of declared ones.
Using strictly
, especially for a library, must be a well-thought-out process as it impacts downstream consumers.
At the same time, if used correctly, it will help consumers understand what combination of libraries does not work together in their context.
See overriding dependency version for more information.
Rich version information will be preserved in the Gradle Module Metadata format.
However conversion to Ivy or Maven metadata formats will be lossy.
The highest level will be published, that is |
Rich version declaration is accessed through the version
DSL method on a dependency or constraint declaration, which gives access to MutableVersionConstraint:
dependencies {
implementation("org.slf4j:slf4j-api") {
version {
strictly("[1.7, 1.8[")
prefer("1.7.25")
}
}
constraints {
add("implementation", "org.springframework:spring-core") {
version {
require("4.2.9.RELEASE")
reject("4.3.16.RELEASE")
}
}
}
}
dependencies {
implementation('org.slf4j:slf4j-api') {
version {
strictly '[1.7, 1.8['
prefer '1.7.25'
}
}
constraints {
implementation('org.springframework:spring-core') {
version {
require '4.2.9.RELEASE'
reject '4.3.16.RELEASE'
}
}
}
}