How does maven sort version numbers?
Solution 1:
Since version 3.0, Maven uses a consistent system to compare version numbers for both individual versions and version ranges. The system now makes a lot of sense, once you've understood a few gotchas.
All comparisons are now done by ComparableVersion, which says:
- mixing of '
-
' (dash) and '.
' (dot) separators,- transition between characters and digits also constitutes a separator:
1.0alpha1
=>[1, 0, alpha, 1]
- unlimited number of version components,
- version components in the text can be digits or strings,
- strings are checked for well-known qualifiers and the qualifier ordering is used for version ordering. Well-known qualifiers (case insensitive) are:
alpha
ora
beta
orb
milestone
orm
rc
orcr
snapshot
- (the empty string) or
ga
orfinal
sp
- Unknown qualifiers are considered after known qualifiers, with lexical order (always case insensitive),
- a dash usually precedes a qualifier, and is always less important than something preceded with a dot.
This means that versions come out in the following order, which I think makes perfect sense, apart from 1.0-SNAPSHOT right in the middle:
1.0-beta1-SNAPSHOT
1.0-beta1
1.0-beta2-SNAPSHOT
1.0-rc1-SNAPSHOT
1.0-rc1
1.0-SNAPSHOT
1.0
1.0-sp
1.0-whatever
1.0.1
The main gotcha I found in all this is that snapshot
comes after beta
or rc
, so you can't have a development version of 1.0-SNAPSHOT
, then release 1.0-beta1
or 1.0-rc1
and have Maven understand that those are later.
Also note that 1.0-beta-1
is exactly the same as 1.0beta1
, and 1.0
is exactly the same as 1
or 1.0.0
.
Version ranges now work (nearly) the way you'd expect, too. For example, [1.0-alpha-SNAPSHOT,1.0]
will find 1.0-beta1-SNAPSHOT
, 1.0-beta1
, 1.0-rc1-SNAPSHOT
, 1.0-rc1
, 1.0-SNAPSHOT
or 1.0
, preferring later items over earlier ones. This is fully supported by mvn versions:resolve
, M2Eclipse and so on.
Solution 2:
This is a test that was written directly against the ComparableVersion class from Maven.
package org.codehaus.mojo.buildhelper.versioning;
import org.apache.maven.artifact.versioning.ComparableVersion;
import org.junit.Assert;
import org.junit.Test;
public class TempTest {
@Test
public void testVersions() {
Assert.assertTrue(new ComparableVersion("1.0-beta1-SNAPSHOT").compareTo(
new ComparableVersion("1.0-beta1")) < 0);
Assert.assertTrue(new ComparableVersion("1.0-beta1").compareTo(
new ComparableVersion("1.0-beta2-SNAPSHOT")) < 0);
Assert.assertTrue(new ComparableVersion("1.0-beta2-SNAPSHOT").compareTo(
new ComparableVersion("1.0-rc1-SNAPSHOT")) < 0);
Assert.assertTrue(new ComparableVersion("1.0-rc1-SNAPSHOT").compareTo(
new ComparableVersion("1.0-rc1")) < 0);
Assert.assertTrue(new ComparableVersion("1.0-rc1").compareTo(
new ComparableVersion("1.0-SNAPSHOT")) < 0);
Assert.assertTrue(new ComparableVersion("1.0-SNAPSHOT").compareTo(
new ComparableVersion("1.0")) < 0);
Assert.assertTrue(new ComparableVersion("1.0").compareTo(
new ComparableVersion("1")) == 0);
Assert.assertTrue(new ComparableVersion("1.0").compareTo(
new ComparableVersion("1.0-sp")) < 0);
Assert.assertTrue(new ComparableVersion("1.0-sp").compareTo(
new ComparableVersion("1.0-whatever")) < 0);
Assert.assertTrue(new ComparableVersion("1.0-whatever").compareTo(
new ComparableVersion("1.0.1")) < 0);
}
}
This test asserts that the following versions are considered to be from lowest to highest by Maven:
- 1.0-beta1-SNAPSHOT
- 1.0-beta1
- 1.0-beta2-SNAPSHOT
- 1.0-rc1-SNAPSHOT
- 1.0-rc1
- 1.0-SNAPSHOT
- 1.0 and 1 (these are equal)
- 1.0-sp
- 1.0-whatever
- 1.0.1
Solution 3:
Your assumption about using major/minor/incremtal/ etc. is simply wrong. The comparision is done in ComparableVersion which contains the implementation. The ctor will call parseVersion(...)
which uses ComparableVersion
which is stored as instance in DefaultArtifactVersion
and it's used during the compareTo(..)
There are parts like getMajor..
, etc. but those are not working correctly. This is the reason why will be marked deprecated.
The information by Stehpen Collony is true for Maven 2 but not for Maven 3 anymore.