2323import java .util .ArrayList ;
2424import java .util .Arrays ;
2525import java .util .Deque ;
26+ import java .util .HashMap ;
2627import java .util .Iterator ;
2728import java .util .List ;
2829import java .util .Locale ;
29- import java .util .Properties ;
30+ import java .util .Map ;
3031
3132/**
3233 * <p>
4041 * <code>1.0alpha1 => [1, 0, alpha, 1]</code></li>
4142 * <li>unlimited number of version components,</li>
4243 * <li>version components in the text can be digits or strings,</li>
43- * <li>strings are checked for well-known qualifiers and the qualifier ordering is used for version ordering.
44- * Well-known qualifiers (case insensitive) are:<ul>
45- * <li><code>alpha</code> or <code>a</code></li>
46- * <li><code>beta</code> or <code>b</code></li>
47- * <li><code>milestone</code> or <code>m</code></li>
48- * <li><code>rc</code> or <code>cr</code></li>
49- * <li><code>snapshot</code></li>
50- * <li><code>(the empty string)</code> or <code>ga</code> or <code>final</code></li>
51- * <li><code>sp</code></li>
52- * </ul>
53- * Unknown qualifiers are considered after known qualifiers, with lexical order (always case insensitive),
54- * </li>
44+ * <li>
45+ * Following semver rules is encouraged, and some qualifiers are discouraged (no matter the case):
46+ * <ul>
47+ * <li> The usage of 'CR' qualifier is discouraged. Use 'RC' instead. </li>
48+ * <li> The usage of 'Final', 'GA', and 'Release' qualifiers is discouraged. Use no qualifier instead. </li>
49+ * <li> The usage of 'SP' qualifier is discouraged. Increment the patch version instead. </li>
50+ * </ul>
51+ * String qualifiers are ordered lexically (case insensitive), with the following exceptions:
52+ * <ul>
53+ * <li><code> alpha = a < beta = b < milestone = m < rc = cr
54+ * < snapshot < '' = final = ga = release < sp </code></li>
55+ * <li>Other qualifiers are ordered lexically (case insensitive),
56+ * and considered less than Snapshot and Release.</li>
57+ * </ul>
58+ * </li>
5559 * <li>a hyphen usually precedes a qualifier, and is always less important than digits/number, for example
5660 * {@code 1.0.RC2 < 1.0-RC3 < 1.0.1}; but prefer {@code 1.0.0-RC1} over {@code 1.0.0.RC1}, and more
5761 * generally: {@code 1.0.X2 < 1.0-X3 < 1.0.1} for any string {@code X}; but prefer {@code 1.0.0-X1}
5862 * over {@code 1.0.0.X1}.</li>
5963 * </ul>
6064 *
61- * @see <a href="https://cwiki .apache.org/confluence/display/MAVENOLD/Versioning">"Versioning" on Maven Wiki </a>
65+ * @see <a href="https://maven .apache.org/pom.html#Version_Order_Specification">Version Order Specification </a>
6266 * @author <a href="mailto:kenney@apache.org">Kenney Westerhof</a>
6367 * @author <a href="mailto:hboutemy@apache.org">Hervé Boutemy</a>
6468 */
@@ -307,23 +311,22 @@ public String toString() {
307311 * Represents a string in the version item list, usually a qualifier.
308312 */
309313 private static class StringItem implements Item {
310- private static final List <String > QUALIFIERS =
311- Arrays .asList ("alpha" , "beta" , "milestone" , "rc" , "snapshot" , "" , "sp" );
314+ private static final List <String > QUALIFIERS = Arrays .asList ("snapshot" , "" , "sp" );
312315
313- private static final Properties ALIASES = new Properties ( );
316+ private static final Map < String , String > ALIASES = new HashMap <>( 4 );
314317
315318 static {
316- ALIASES .put ("ga " , "" );
319+ ALIASES .put ("cr " , "rc " );
317320 ALIASES .put ("final" , "" );
321+ ALIASES .put ("ga" , "" );
318322 ALIASES .put ("release" , "" );
319- ALIASES .put ("cr" , "rc" );
320323 }
321324
322325 /**
323- * A comparable value for the empty-string qualifier. This one is used to determine if a given qualifier makes
326+ * An index value for the empty-string qualifier. This one is used to determine if a given qualifier makes
324327 * the version older than one without a qualifier, or more recent.
325328 */
326- private static final String RELEASE_VERSION_INDEX = String . valueOf ( QUALIFIERS .indexOf ("" ) );
329+ private static final int RELEASE_VERSION_INDEX = QUALIFIERS .indexOf ("" );
327330
328331 private final String value ;
329332
@@ -343,7 +346,7 @@ private static class StringItem implements Item {
343346 default :
344347 }
345348 }
346- this .value = ALIASES .getProperty (value , value );
349+ this .value = ALIASES .getOrDefault (value , value );
347350 }
348351
349352 @ Override
@@ -353,7 +356,7 @@ public int getType() {
353356
354357 @ Override
355358 public boolean isNull () {
356- return ( comparableQualifier ( value ). compareTo ( RELEASE_VERSION_INDEX ) == 0 ) ;
359+ return QUALIFIERS . indexOf ( value ) == RELEASE_VERSION_INDEX ;
357360 }
358361
359362 /**
@@ -368,18 +371,41 @@ public boolean isNull() {
368371 *
369372 * @param qualifier
370373 * @return an equivalent value that can be used with lexical comparison
374+ * @deprecated Use {@link #compareQualifiers(String, String)} instead
371375 */
376+ @ Deprecated
372377 public static String comparableQualifier (String qualifier ) {
373- int i = QUALIFIERS .indexOf (qualifier );
378+ int index = QUALIFIERS .indexOf (qualifier ) + 1 ;
379+
380+ return index == 0 ? ("0-" + qualifier ) : String .valueOf (index );
381+ }
382+
383+ /**
384+ * Compare the qualifiers of two artifact versions.
385+ *
386+ * @param qualifier1 qualifier of first artifact
387+ * @param qualifier2 qualifier of second artifact
388+ * @return a negative integer, zero, or a positive integer as the first argument is less than, equal to, or
389+ * greater than the second
390+ */
391+ public static int compareQualifiers (String qualifier1 , String qualifier2 ) {
392+ int i1 = QUALIFIERS .indexOf (qualifier1 );
393+ int i2 = QUALIFIERS .indexOf (qualifier2 );
394+
395+ // if both pre-release, then use natural lexical ordering
396+ if (i1 == -1 && i2 == -1 ) {
397+ return qualifier1 .compareTo (qualifier2 );
398+ }
374399
375- return i == -1 ? (QUALIFIERS .size () + "-" + qualifier ) : String .valueOf (i );
400+ // 'other qualifier' < 'snapshot' < '' < 'sp'
401+ return Integer .compare (i1 , i2 );
376402 }
377403
378404 @ Override
379405 public int compareTo (Item item ) {
380406 if (item == null ) {
381407 // 1-rc < 1, 1-ga > 1
382- return comparableQualifier ( value ). compareTo ( RELEASE_VERSION_INDEX );
408+ return Integer . compare ( QUALIFIERS . indexOf ( value ), RELEASE_VERSION_INDEX );
383409 }
384410 switch (item .getType ()) {
385411 case INT_ITEM :
@@ -388,7 +414,7 @@ public int compareTo(Item item) {
388414 return -1 ; // 1.any < 1.1 ?
389415
390416 case STRING_ITEM :
391- return comparableQualifier (value ). compareTo ( comparableQualifier ((( StringItem ) item ).value ) );
417+ return compareQualifiers (value , (( StringItem ) item ).value );
392418
393419 case LIST_ITEM :
394420 return -1 ; // 1.any < 1-1
0 commit comments