How does dynamic dependency resolution decide which version to use?

The docs say

Once each repository has been inspected for the module, Gradle will choose the ‘best’ one to use. This is done using the following criteria: >

For a dynamic version, a ‘higher’ static version is preferred over a ‘lower’ version. > Modules declared by a module descriptor file (ivy or pom file) are preferred over modules that have an artifact file only. > Modules from earlier repositories are preferred over modules in later repositories.

Am I correct in assuming this states the precedence in which the rules are applied?

e.g. if I have a dependency foo:1.0.1 in repository X and I have foo:1.0.2 in repository Y then irrespective of the order the repositories are listed, it will select foo:1.0.2

Cheers Matt

That’s correct, assuming that you’re declaring your dependency as ‘foo:1.0.+’ (or similar) Gradle will find the highest matching version and use it. For dynamic versions like this, all repositories are inspected.

Order of repositories is significant for static dependencies however (‘foo:1.0.1’); the repositories are inspected in order and the first one with a matching module will be used. In the normal case this makes no difference, as the assumption is that ‘foo:1.0.1’ in repo1 is identical to ‘foo:1.0.1’ in repo2.

OK thanks. Am I correct in thinking this in interacts with the dynamic revision cache as follows…

  • ‘foo:1.0.1’ is published to a repository * I build bar (with default dynamic revision cache timeout) and it resolves ‘foo:1.0+’ to ‘foo:1.0.1’ * ‘foo:1.0.2’ is published * I rebuild bar (same config), it resolves ‘foo:1.0+’ to ‘foo:1.0.1’ * 24 hrs pass (or I pass ‘–refresh-dependencies’ * I rebuild bar (same config), it resolves ‘foo:1.0+’ to ‘foo:1.0.2’


If so, when does the cache expiry? the clock starts after it first resolves or from the last time the cache isused?

Cheers Matt

Yes, the interaction you describe is correct.

The cache expiry can be controlled as described in

The cache expiry “timer” starts when the module is resolved and placed in the cache. When a cached entry was last used does not impact when it will expire from the cache.

OK thanks. This is exactly what I need.

is the cache per project or global? i.e. if I build projectX and it resolves against ‘foo:1.0’ and then some time later I build projectY (for the first time) and foo is now at ‘foo:1.1’, do it resolve against the fresh ‘foo:1.1’ and cache that independently or does it share the existing cached view from projectX?

Caches are per-repository, which means if both projects share a repository (same URL/credentials/etc) then they will share the cached view of projects in that repository.

So if you resolve ‘foo:1.+’ from projectX and it resolves to ‘foo:1.0’, then resolve ‘foo:1.+’ from projectY within 24 hours, projectY will also get ‘foo:1.0’ even if ‘foo’ has been upgraded in the meantime. (This is assuming that projectX and projectY resolve from the same repository.)

You can tweak the 24 hr timeout by using ‘–refresh-dependencies’ or ‘cacheDynamicVersionsFor’.

what if I want 1.2.+ or 1.2+ to map only x.x.x (3 digit patterns) instead of x.x.x.x 4 or more digit patterns for versions of a dependency. i.e. 1.2+ or 1.2.+ should get me the latest of "1.2.0 or 1.2.1 or 1.2.2 whichever exists greater at a given point of time.