How do I ensure all artifacts with same group have same version?

We use a lot of org.springframework in our code, and declare all dependencies using a specific version (4.1.0.RELEASE).

However, when another library introduces an otherwise unused spring module as a transitive dependency, this new module may easily have the “wrong” version. For example, “spring-ws-core” depends on spring-oxm (partial listing):

±-- org.springframework.ws:spring-ws-core:2.2.0.RELEASE

|

±-- org.springframework:spring-core:4.0.5.RELEASE -> 4.1.0.RELEASE (*)

|

±-- org.springframework:spring-oxm:4.0.5.RELEASE

|

|

±-- org.springframework:spring-beans:4.0.5.RELEASE -> 4.1.0.RELEASE (*)

|

|

— org.springframework:spring-core:4.0.5.RELEASE -> 4.1.0.RELEASE (*)

Here you can see that all the dependencies we declared directly use spring 4.1.0.RELEASE. We did not use spring-oxm, but spring-ws-core introduced that a dependency on version 4.0.5.RELEASE, and now we have a mix of both 4.0.5 and 4.1.0 in the shipping product.

The question is this:

  • What is the best way to ensure that all artifacts of a group (e.g. org.springframework) have same version?

(The same topic was visited “over two years ago”, at http://forums.gradle.org/gradle/topics/concise_syntax_for_specifying_the_version_for_any_artifact_within_a_group, but referred to stuff being added in gradle 1.2, so perhaps there is now a better answer?)

You can customize the resolution strategy.

configurations.all {

resolutionStrategy.eachDependency {

if (it.requested.group == ‘org.springframework’) {

it.useVersion ‘4.1.0.RELEASE’

}

}

}

Splendid. Works like a charm!

Beyond the functional requirement (which is now solved), I could have wanted a simpler and more declarative mechanism:

  • It should not be necessary to specify versions twice (first in the dependencies-section, and then in the resolutionStrategy) * It should ideally be more declarative (rather than imperative), as in somehow saying “org.springframework:*:4.1.0.RELEASE”

That is probably a bigger question, and definitely out of scope of my request, so I’m happy.

Your first issue could be solved by simply using properties for dependency versions.

ext {

springVersion = ‘4.1.0.RELEASE’

}

dependencies {

compile “org.springframework:spring-context:${springVersion}”

}

Your second concern is valid, but I think there is a balance between providing specialized DSL and simply exposing the Gradle API for any given use case. This is arguably a fairly common use case that might warrant what you are describing but the current solution I posted above solves this use case in addition to many others.

Perhaps you could at least write a method called something like “constrainRelatedArtifacts()”, which takes a map, where the key is a group name, and the value is the expected version to constrain all the artifacts in that group to.

Mark,

We already use properties, and the issue appears only when transitive dependencies from the same group is brought in. The original post describes this in more detail, but in our scenario we depend directly on lots of artifacts from org.springframework and org.springframework.ws – and then the spring-ws ones bring in other org.springframework artifacts that we otherwise don’t need, using whatever version the spring-ws project used.

David,

That is indeed an option, but that method itself is similar to what is specified above (which is very nice, not to forget!). I guess I just dream of the perfect, declarative DSL-solution :slight_smile:

Anyway, thank you both for your time. My problem is solved :slight_smile:

Concerning your point about “that method itself is similar to what is specified above”, that’s exactly the point. I’m suggesting you encapsulate your logic into a reusable method. As a result, you will have somewhat self-documenting code (assuming you give the method a good name), along with a concise reference to the group and version.

There are no perfect solutions. You can usually improve what you have, balancing cost and tradeoffs.