Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why version matching doesn't work in Maven?

Tags:

maven-2

This is my pom.xml (fragment of it):

...
<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-entitymanager</artifactId>
    <version>[3.0,)</version>
</dependency>
...

This is what mvn tells me:

Couldn't find a version in [3.2.0.cr2, 3.2.0.ga, 3.3.1.ga] to match range [3.0,)

Why?

like image 826
yegor256 Avatar asked Jul 27 '10 14:07

yegor256


1 Answers

The old X.Y.Z.ga naming scheme used by Hibernate (see this page for the new JBoss conventions) is not following Maven's format and might not work well with the version comparison algorithm. Quoting the Version number rules:

The current implementation of DefaultArtifactVersion in the core of Maven expects that version numbers will have a very specific format:

<MajorVersion [> . <MinorVersion [> . <IncrementalVersion ] ] [> - <BuildNumber | Qualifier ]>

Where MajorVersion, MinorVersion, IncrementalVersion and BuildNumber are all numeric and Qualifier is a string. If your version number does not match this format, then the entire version number is treated as being the Qualifier.

If your version numbers do not match this scheme, you may face issues with

  • version ranges (unfortunately there is nothing that the versions-maven-plugin can do to help you with your problems with version ranges and your version numbering scheme... well you could replace your version ranges with properties and use the update-properties goal)
  • goals in this plugin that sort versions, for example update-properties (you can do things to help with these kinds of problems)

The algorithm is explained in details in Dependency Mediation and Conflict Resolution:

Default Version comparison definition

The default specification should be composed as follows:

<major>.<minor>.<revision>([ -<qualififer> ] | [ -<build> ])

where:

  • the qualifier section is optional (and is SNAPSHOT, alpha-1, alpha-2)
  • the build section is optional (and increments starting at 1 if specified)
  • any '0' build or revision elements can be omitted.
  • only one of build and qualifier can be given (note that the timestamped qualifier includes a build number, but this is not the same)
  • the build number is for those that repackage the original artifact (eg, as is often done with rpms)

For ordering, the following is done in order until an element is found that are not equal:

  • numerical comparison of major version
  • numerical comparison of minor version
  • if revision does not exist, add ".0" for comparison purposes
  • numerical comparison of revision
  • if qualifier does not exist, it is newer than if it does
  • case-insensitive string comparison of qualifier
    • this ensures timestamps are correctly ordered, and SNAPSHOT is newer than an equivalent timestamp
    • this also ensures that beta comes after alpha, as does rc
  • if no qualifier, and build does not exist, add "-0" for comparison purposes
  • numerical comparison of build

Note also the proposed extension from a user in an rpm environment: Extending Maven 2.0 Dependencies

To sum up:

  • 3.2.0.cr2, 3.2.0.ga, 3.3.1.ga are treated as qualifier (i.e. they somehow become 0.0.0-3.2.0.cr2 etc)
  • Knowing this, you can maybe fool Maven using a [0.0.0-3.0,) range.
  • But this will match more versions than wanted (e.g. 2.x) so beware of unexpected side effects.

Actually, my recommendation is to not use version ranges at all, they are just bad for reproducible builds.

See also

  • Dependency Version Ranges
  • Improve default support for version schemes
like image 58
Pascal Thivent Avatar answered Oct 06 '22 00:10

Pascal Thivent