10

As Maven (client) and IvyResolver (used by Gradle) Bundler solves libraries dependencies that was declared on configuration file (Gemfile for bundler). However, after that Bundler saves dependency resolution on Gemfile.lock. It allows other developers use exactly the same libraries.

For instance, Maven use a determinist by not clear way to resolve conflict in dependency resolution. For example, specifying version as ...

<version>1.0.1</version>

is not guarantee that version will be used. And specifying version as ...

<version>[1.0.0,2.0.0)</version>

give us almost no guarantee.

Yes, I could write manually all versions listed by

mvn dependency:resolve

But, is there any automatic way to do that?

To be very clear: is there any equivalent to Gemfile.lock in Maven or Gradle?


Java developers, if you are not familiar with Gemfile.lock, Bundler, please check:

http://bundler.io/v1.3/rationale.html

The important part I copy below:

Checking Your Code into Version Control

After developing your application for a while, check in the application together with the Gemfile and Gemfile.lock snapshot. Now, your repository has a record of the exact versions of all of the gems that you used the last time you know for sure that the application worked. Keep in mind that while your Gemfile lists only three gems (with varying degrees of version strictness), your application depends on dozens of gems, once you take into consideration all of the implicit requirements of the gems you depend on.

This is important: the Gemfile.lock makes your application a single package of both your own code and the third-party code it ran the last time you know for sure that everything worked. Specifying exact versions of the third-party code you depend on in your Gemfile would not provide the same guarantee, because gems usually declare a range of versions for their dependencies.

The next time you run bundle install on the same machine, bundler will see that it already has all of the dependencies you need, and skip the installation process.

"You are not correct. Maven can garantee the version"

Yes, right. If you have a version declared in the very pom.xml, maven uses it. But, if it was declared in parent pom, this garantee is vanished.

Dependency mediation - this determines what version of a dependency will be used when multiple versions of an artifact are encountered. Currently, Maven 2.0 only supports using the "nearest definition" which means that it will use the version of the closest dependency to your project in the tree of dependencies. You can always guarantee a version by declaring it explicitly in your project's POM. Note that if two dependency versions are at the same depth in the dependency tree, until Maven 2.0.8 it was not defined which one would win, but since Maven 2.0.9 it's the order in the declaration that counts: the first declaration wins.

"nearest definition" means that the version used will be the closest one to your project in the tree of dependencies, eg. if dependencies for A, B, and C are defined as A -> B -> C -> D 2.0 and A -> E -> D 1.0, then D 1.0 will be used when building A because the path from A to D through E is shorter. You could explicitly add a dependency to D 2.0 in A to force the use of D 2.0

Oh, looks like this is the opposite of DRY principle.

rdllopes
  • 4,897
  • 4
  • 19
  • 36

3 Answers3

6

The nebula.gradle-dependency-lock plugin does just that.

PS: Gradle doesn't use Ivy anymore (if that's what you mean by IvyResolver).

Peter Niederwieser
  • 121,412
  • 21
  • 324
  • 259
2

The solution to locking dependencies is to use the <dependencyManagement> section of the current pom or its parent and never declare <version>s in the <dependencies> section of your pom.

You can enforce this behavior with the Pedanic Pom Enforcer plugin (so that only the parent project can declare dependency versions). You can also use the enforcer plugin to completely ban all transitive dependencies or various subsets (I don't even think gradle or bundle have this level of configurability). Some really like this behavior as you can make it so that you have declare every dependency which makes you cognizant of how bloated/coupled your app/library might be.

Yes this not that DRY as you basically have to declare the package twice (once in dependencyManagement and the second time without version in dependencies). This is even worse if you decide to ban all transitives. You can mitigate the DRY issue by using imports (ie bom:bill of material pom files) and/or parent poms. Some company's like my own have a master parent pom with every dependency that every project is using (consequently locking the version of libraries across projects). Remember the parent or imported pom can be versioned as well!

As for the gem lock file behavior there isn't really anything analogous... err its there its just not as KISS (that being said I have been severely burnt by Gem.lock and prefer the maven/gradle way... each has its merits). You could write a plugin though based off the maven dependency plugin (ie dump the analyzed dependencies to file) .

Adam Gent
  • 47,843
  • 23
  • 153
  • 203
-2

You are not correct here. If you explicitely state

<version>1.0.1</version>

in your pom, it is garanteed that this version will be used over transitive dependencies that could use different version.

gizmo
  • 11,819
  • 6
  • 44
  • 61
  • 1) you are not correct here. maven.apache.org/enforcer/enforcer-rules/versionRanges.html It will resolve to 1.0.1 unless a collision occurs. "The default Maven meaning for 1.0 is everything (,) but with 1.0 recommended. Obviously this doesn't work for enforcing versions here, so it has been redefined as a minimum version." 2) sorry, but that was not my question. – rdllopes Nov 19 '14 at 13:37
  • Sorry, but you are wrong. You are looking at the the wrong documentation. The enforcer plugin is not what you need to fix your dependencies. The proper documentation is http://docs.codehaus.org/display/MAVEN/Dependency+Mediation+and+Conflict+Resolution and if you look at the "Forcing a version" section, you'll see that I'm both right and that is answer your need. – gizmo Nov 19 '14 at 14:03
  • In that page... >> "Soft" requirement on 1.0 (just a recommendation - helps select the correct version if it matches all ranges) However, again... it is not answer for the question. I don't want to write all dependencies manually with a very specific version. Can you read the question again, I have edited to avoid confusion. I am sorry. – rdllopes Nov 19 '14 at 14:18
  • The section your are reading is for *transitive dependencies*, that's why I explicitely told you to read the "Forcing a version" section. And manually fixing every single direct dependency is the correct way to do it with maven. Like it or not. – gizmo Nov 19 '14 at 14:22
  • Believe me, that is why exist the "Hard requirement". You should read *Conflict Resolution* section to understand. But, I can't believe that manually fixing every single dependency is the only way with maven. I was hoping dependency-plugin could do the trick. http://maven.apache.org/plugins/maven-dependency-plugin/ – rdllopes Nov 19 '14 at 14:41