Skip to content
Skip to breadcrumbs
Skip to header menu
Skip to action menu
Skip to quick search
Quick Search
Browse
Pages
Blog
Labels
Attachments
Mail
Advanced
What’s New
Space Directory
Feed Builder
Keyboard Shortcuts
Confluence Gadgets
Log In
Sign Up
Dashboard
Maven
Copy Page
You are not logged in. Any changes you make will be marked as
anonymous
. You may want to
Log In
if you already have an account. You can also
Sign Up
for a new account.
This page is being edited by
.
Paragraph
Paragraph
Heading 1
Heading 2
Heading 3
Heading 4
Heading 5
Heading 6
Preformatted
Quote
Bold
Italic
Underline
More colours
Strikethrough
Subscript
Superscript
Monospace
Clear Formatting
Bullet list
Numbered list
Outdent
Indent
Align left
Align center
Align right
Link
Table
Insert
Insert Content
Image
Link
Attachment
Symbol
Emoticon
Wiki Markup
Horizontal rule
tinymce.confluence.insert_menu.macro_desc
Info
JIRA Issue
Status
Gallery
Tasklist
Table of Contents
Other Macros
Page Layout
No Layout
Two column (simple)
Two column (simple, left sidebar)
Two column (simple, right sidebar)
Three column (simple)
Two column
Two column (left sidebar)
Two column (right sidebar)
Three column
Three column (left and right sidebars)
Undo
Redo
Find/Replace
Keyboard Shortcuts Help
<h1>Improve default support for version schemes</h1> <p>The <a href="http://svn.apache.org/viewvc/maven/artifact/trunk/src/main/java/org/apache/maven/artifact/versioning/DefaultArtifactVersion.java?view=markup">current implementation for version schemes</a> is rather limited. It only supports 5 properties:</p> <ol> <li>Major versoin</li> <li>Minor version</li> <li>Incremental version (bugfix)</li> <li>Build number</li> <li>A Qualifier.</li> </ol> <h3>Flaws</h3> <p>Other than the limitation of supported versions, the current implementation has several flaws:</p> <ul> <li>It only supports the following schemes: <ul> <li>'positiveInteger-buildnumber' where buildnumber doesn't start with '0' and has to be</li> <li>'positiveinteger-qualifier'</li> <li>positiveInteger(.positiveInteger(.positiveInteger))-(buildNr|qualifier)</li> </ul> </li> <li>Inconsistent/unintuitive parsing: <ul> <li>in something-X, where X is [1..9], X will be a buildnumber</li> <li>in something-0X, where X is any string, '0X' will be a qualifier</li> <li>something.0something will yield 0.0.0.0-something.0something</li> <li>something.NaN will also yield 0.0.0.0-something.NaN</li> </ul> </li> <li>getBuildNumber returns '0' when no buildnumber is specified, yet you can never specify 0 as a buildnumber</li> <li>qualifiers are sorted lexically</li> <li>if a qualifier is a prefix of another, the shorter one is considered newer (example:'1.0-alpha10' is considered older than '1.0-alpha1')</li> </ul> <p>The <a href="http://svn.apache.org/viewvc/maven/artifact/trunk/src/test/java/org/apache/maven/artifact/versioning/DefaultArtifactVersionTest.java?view=markup">unit tests that are there to test comparison</a> only check for a few cases with snapshots. When all tests<br /> (version A < version B) are expanded to also test for SNAPSHOTs (version A-SNAPSHOT < version B-SNAPSHOT) a<br /> lot of the tests fail.</p> <table class="confluenceTable"><tbody> <tr> <th class="confluenceTh"><p> Left </p></th> <th class="confluenceTh"><p> Op </p></th> <th class="confluenceTh"><p> Right </p></th> <th class="confluenceTh"><p> </p></th> <th class="confluenceTh"><p> Left </p></th> <th class="confluenceTh"><p> Op </p></th> <th class="confluenceTh"><p> Right </p></th> <th class="confluenceTh"><p> </p></th> </tr> <tr> <td class="confluenceTd"><p> 1 </p></td> <td class="confluenceTd"><p> = </p></td> <td class="confluenceTd"><p> 1 </p></td> <td class="confluenceTd"><p> <img class="emoticon emoticon-tick" data-emoticon-name="tick" border="0" src="/s/en_GB/3278/15/_/images/icons/emoticons/check.png" alt="(tick)" title="(tick)" /> </p></td> <td class="confluenceTd"><p> 1-SNAPSHOT </p></td> <td class="confluenceTd"><p> = </p></td> <td class="confluenceTd"><p> 1-SNAPSHOT </p></td> <td class="confluenceTd"><p> <img class="emoticon emoticon-tick" data-emoticon-name="tick" border="0" src="/s/en_GB/3278/15/_/images/icons/emoticons/check.png" alt="(tick)" title="(tick)" /> </p></td> </tr> <tr> <td class="confluenceTd"><p> 1 </p></td> <td class="confluenceTd"><p> < </p></td> <td class="confluenceTd"><p> 2 </p></td> <td class="confluenceTd"><p> <img class="emoticon emoticon-tick" data-emoticon-name="tick" border="0" src="/s/en_GB/3278/15/_/images/icons/emoticons/check.png" alt="(tick)" title="(tick)" /> </p></td> <td class="confluenceTd"><p> 1-SNAPSHOT </p></td> <td class="confluenceTd"><p> < </p></td> <td class="confluenceTd"><p> 2-SNAPSHOT </p></td> <td class="confluenceTd"><p> <img class="emoticon emoticon-tick" data-emoticon-name="tick" border="0" src="/s/en_GB/3278/15/_/images/icons/emoticons/check.png" alt="(tick)" title="(tick)" /> </p></td> </tr> <tr> <td class="confluenceTd"><p> 1.5 </p></td> <td class="confluenceTd"><p> < </p></td> <td class="confluenceTd"><p> 2 </p></td> <td class="confluenceTd"><p> <img class="emoticon emoticon-tick" data-emoticon-name="tick" border="0" src="/s/en_GB/3278/15/_/images/icons/emoticons/check.png" alt="(tick)" title="(tick)" /> </p></td> <td class="confluenceTd"><p> 1.5-SNAPSHOT </p></td> <td class="confluenceTd"><p> < </p></td> <td class="confluenceTd"><p> 2-SNAPSHOT </p></td> <td class="confluenceTd"><p> <img class="emoticon emoticon-tick" data-emoticon-name="tick" border="0" src="/s/en_GB/3278/15/_/images/icons/emoticons/check.png" alt="(tick)" title="(tick)" /> </p></td> </tr> <tr> <td class="confluenceTd"><p> 1 </p></td> <td class="confluenceTd"><p> < </p></td> <td class="confluenceTd"><p> 2.5 </p></td> <td class="confluenceTd"><p> <img class="emoticon emoticon-tick" data-emoticon-name="tick" border="0" src="/s/en_GB/3278/15/_/images/icons/emoticons/check.png" alt="(tick)" title="(tick)" /> </p></td> <td class="confluenceTd"><p> 1-SNAPSHOT </p></td> <td class="confluenceTd"><p> < </p></td> <td class="confluenceTd"><p> 2.5-SNAPSHOT </p></td> <td class="confluenceTd"><p> <img class="emoticon emoticon-tick" data-emoticon-name="tick" border="0" src="/s/en_GB/3278/15/_/images/icons/emoticons/check.png" alt="(tick)" title="(tick)" /> </p></td> </tr> <tr> <td class="confluenceTd"><p> 1 </p></td> <td class="confluenceTd"><p> = </p></td> <td class="confluenceTd"><p> 1.0 </p></td> <td class="confluenceTd"><p> <img class="emoticon emoticon-tick" data-emoticon-name="tick" border="0" src="/s/en_GB/3278/15/_/images/icons/emoticons/check.png" alt="(tick)" title="(tick)" /> </p></td> <td class="confluenceTd"><p> 1-SNAPSHOT </p></td> <td class="confluenceTd"><p> = </p></td> <td class="confluenceTd"><p> 1.0-SNAPSHOT </p></td> <td class="confluenceTd"><p> <img class="emoticon emoticon-tick" data-emoticon-name="tick" border="0" src="/s/en_GB/3278/15/_/images/icons/emoticons/check.png" alt="(tick)" title="(tick)" /> </p></td> </tr> <tr> <td class="confluenceTd"><p> 1 </p></td> <td class="confluenceTd"><p> = </p></td> <td class="confluenceTd"><p> 1.0.0 </p></td> <td class="confluenceTd"><p> <img class="emoticon emoticon-tick" data-emoticon-name="tick" border="0" src="/s/en_GB/3278/15/_/images/icons/emoticons/check.png" alt="(tick)" title="(tick)" /> </p></td> <td class="confluenceTd"><p> 1-SNAPSHOT </p></td> <td class="confluenceTd"><p> = </p></td> <td class="confluenceTd"><p> 1.0.0-SNAPSHOT </p></td> <td class="confluenceTd"><p> <img class="emoticon emoticon-tick" data-emoticon-name="tick" border="0" src="/s/en_GB/3278/15/_/images/icons/emoticons/check.png" alt="(tick)" title="(tick)" /> </p></td> </tr> <tr> <td class="confluenceTd"><p> 1.0 </p></td> <td class="confluenceTd"><p> < </p></td> <td class="confluenceTd"><p> 1.1 </p></td> <td class="confluenceTd"><p> <img class="emoticon emoticon-tick" data-emoticon-name="tick" border="0" src="/s/en_GB/3278/15/_/images/icons/emoticons/check.png" alt="(tick)" title="(tick)" /> </p></td> <td class="confluenceTd"><p> 1.0-SNAPSHOT </p></td> <td class="confluenceTd"><p> < </p></td> <td class="confluenceTd"><p> 1.1-SNAPSHOT </p></td> <td class="confluenceTd"><p> <img class="emoticon emoticon-tick" data-emoticon-name="tick" border="0" src="/s/en_GB/3278/15/_/images/icons/emoticons/check.png" alt="(tick)" title="(tick)" /> </p></td> </tr> <tr> <td class="confluenceTd"><p> 1.1 </p></td> <td class="confluenceTd"><p> < </p></td> <td class="confluenceTd"><p> 1.2 </p></td> <td class="confluenceTd"><p> <img class="emoticon emoticon-tick" data-emoticon-name="tick" border="0" src="/s/en_GB/3278/15/_/images/icons/emoticons/check.png" alt="(tick)" title="(tick)" /> </p></td> <td class="confluenceTd"><p> 1.1-SNAPSHOT </p></td> <td class="confluenceTd"><p> < </p></td> <td class="confluenceTd"><p> 1.2-SNAPSHOT </p></td> <td class="confluenceTd"><p> <img class="emoticon emoticon-tick" data-emoticon-name="tick" border="0" src="/s/en_GB/3278/15/_/images/icons/emoticons/check.png" alt="(tick)" title="(tick)" /> </p></td> </tr> <tr> <td class="confluenceTd"><p> 1.0.0 </p></td> <td class="confluenceTd"><p> < </p></td> <td class="confluenceTd"><p> 1.1 </p></td> <td class="confluenceTd"><p> <img class="emoticon emoticon-tick" data-emoticon-name="tick" border="0" src="/s/en_GB/3278/15/_/images/icons/emoticons/check.png" alt="(tick)" title="(tick)" /> </p></td> <td class="confluenceTd"><p> 1.0.0-SNAPSHOT </p></td> <td class="confluenceTd"><p> < </p></td> <td class="confluenceTd"><p> 1.1-SNAPSHOT </p></td> <td class="confluenceTd"><p> <img class="emoticon emoticon-tick" data-emoticon-name="tick" border="0" src="/s/en_GB/3278/15/_/images/icons/emoticons/check.png" alt="(tick)" title="(tick)" /> </p></td> </tr> <tr> <td class="confluenceTd"><p> 1.1 </p></td> <td class="confluenceTd"><p> < </p></td> <td class="confluenceTd"><p> 1.2.0 </p></td> <td class="confluenceTd"><p> <img class="emoticon emoticon-tick" data-emoticon-name="tick" border="0" src="/s/en_GB/3278/15/_/images/icons/emoticons/check.png" alt="(tick)" title="(tick)" /> </p></td> <td class="confluenceTd"><p> 1.1-SNAPSHOT </p></td> <td class="confluenceTd"><p> < </p></td> <td class="confluenceTd"><p> 1.2.0-SNAPSHOT </p></td> <td class="confluenceTd"><p> <img class="emoticon emoticon-tick" data-emoticon-name="tick" border="0" src="/s/en_GB/3278/15/_/images/icons/emoticons/check.png" alt="(tick)" title="(tick)" /> </p></td> </tr> <tr> <td class="confluenceTd"><p> 1.0-alpha-1 </p></td> <td class="confluenceTd"><p> < </p></td> <td class="confluenceTd"><p> 1.0 </p></td> <td class="confluenceTd"><p> <img class="emoticon emoticon-tick" data-emoticon-name="tick" border="0" src="/s/en_GB/3278/15/_/images/icons/emoticons/check.png" alt="(tick)" title="(tick)" /> </p></td> <td class="confluenceTd"><p> 1.0-alpha-1-SNAPSHOT </p></td> <td class="confluenceTd"><p> < </p></td> <td class="confluenceTd"><p> 1.0-SNAPSHOT </p></td> <td class="confluenceTd"><p> <img class="emoticon emoticon-cross" data-emoticon-name="cross" border="0" src="/s/en_GB/3278/15/_/images/icons/emoticons/error.png" alt="(error)" title="(error)" /> </p></td> </tr> <tr> <td class="confluenceTd"><p> 1.0-alpha-1 </p></td> <td class="confluenceTd"><p> < </p></td> <td class="confluenceTd"><p> 1.0-alpha-2 </p></td> <td class="confluenceTd"><p> <img class="emoticon emoticon-tick" data-emoticon-name="tick" border="0" src="/s/en_GB/3278/15/_/images/icons/emoticons/check.png" alt="(tick)" title="(tick)" /> </p></td> <td class="confluenceTd"><p> 1.0-alpha-1-SNAPSHOT </p></td> <td class="confluenceTd"><p> < </p></td> <td class="confluenceTd"><p> 1.0-alpha-2-SNAPSHOT </p></td> <td class="confluenceTd"><p> <img class="emoticon emoticon-tick" data-emoticon-name="tick" border="0" src="/s/en_GB/3278/15/_/images/icons/emoticons/check.png" alt="(tick)" title="(tick)" /> </p></td> </tr> <tr> <td class="confluenceTd"><p> 1.0-alpha-1 </p></td> <td class="confluenceTd"><p> < </p></td> <td class="confluenceTd"><p> 1.0-beta-1 </p></td> <td class="confluenceTd"><p> <img class="emoticon emoticon-tick" data-emoticon-name="tick" border="0" src="/s/en_GB/3278/15/_/images/icons/emoticons/check.png" alt="(tick)" title="(tick)" /> </p></td> <td class="confluenceTd"><p> 1.0-alpha-1-SNAPSHOT </p></td> <td class="confluenceTd"><p> < </p></td> <td class="confluenceTd"><p> 1.0-beta-1-SNAPSHOT </p></td> <td class="confluenceTd"><p> <img class="emoticon emoticon-tick" data-emoticon-name="tick" border="0" src="/s/en_GB/3278/15/_/images/icons/emoticons/check.png" alt="(tick)" title="(tick)" /> </p></td> </tr> <tr> <td class="confluenceTd"><p> 1.0 </p></td> <td class="confluenceTd"><p> < </p></td> <td class="confluenceTd"><p> 1.0-1 </p></td> <td class="confluenceTd"><p> <img class="emoticon emoticon-tick" data-emoticon-name="tick" border="0" src="/s/en_GB/3278/15/_/images/icons/emoticons/check.png" alt="(tick)" title="(tick)" /> </p></td> <td class="confluenceTd"><p> 1.0-SNAPSHOT </p></td> <td class="confluenceTd"><p> < </p></td> <td class="confluenceTd"><p> 1.0-1-SNAPSHOT </p></td> <td class="confluenceTd"><p> <img class="emoticon emoticon-cross" data-emoticon-name="cross" border="0" src="/s/en_GB/3278/15/_/images/icons/emoticons/error.png" alt="(error)" title="(error)" /> </p></td> </tr> <tr> <td class="confluenceTd"><p> 1.0-1 </p></td> <td class="confluenceTd"><p> < </p></td> <td class="confluenceTd"><p> 1.0-2 </p></td> <td class="confluenceTd"><p> <img class="emoticon emoticon-tick" data-emoticon-name="tick" border="0" src="/s/en_GB/3278/15/_/images/icons/emoticons/check.png" alt="(tick)" title="(tick)" /> </p></td> <td class="confluenceTd"><p> 1.0-1-SNAPSHOT </p></td> <td class="confluenceTd"><p> < </p></td> <td class="confluenceTd"><p> 1.0-2-SNAPSHOT </p></td> <td class="confluenceTd"><p> <img class="emoticon emoticon-cross" data-emoticon-name="cross" border="0" src="/s/en_GB/3278/15/_/images/icons/emoticons/error.png" alt="(error)" title="(error)" /> </p></td> </tr> <tr> <td class="confluenceTd"><p> 2.0-0 </p></td> <td class="confluenceTd"><p> = </p></td> <td class="confluenceTd"><p> 2.0 </p></td> <td class="confluenceTd"><p> <img class="emoticon emoticon-tick" data-emoticon-name="tick" border="0" src="/s/en_GB/3278/15/_/images/icons/emoticons/check.png" alt="(tick)" title="(tick)" /> </p></td> <td class="confluenceTd"><p> 2.0-0-SNAPSHOT </p></td> <td class="confluenceTd"><p> = </p></td> <td class="confluenceTd"><p> 2.0-SNAPSHOT </p></td> <td class="confluenceTd"><p> <img class="emoticon emoticon-cross" data-emoticon-name="cross" border="0" src="/s/en_GB/3278/15/_/images/icons/emoticons/error.png" alt="(error)" title="(error)" /> </p></td> </tr> <tr> <td class="confluenceTd"><p> 2.0 </p></td> <td class="confluenceTd"><p> < </p></td> <td class="confluenceTd"><p> 2.0-1 </p></td> <td class="confluenceTd"><p> <img class="emoticon emoticon-tick" data-emoticon-name="tick" border="0" src="/s/en_GB/3278/15/_/images/icons/emoticons/check.png" alt="(tick)" title="(tick)" /> </p></td> <td class="confluenceTd"><p> 2.0-SNAPSHOT </p></td> <td class="confluenceTd"><p> < </p></td> <td class="confluenceTd"><p> 2.0-1-SNAPSHOT </p></td> <td class="confluenceTd"><p> <img class="emoticon emoticon-cross" data-emoticon-name="cross" border="0" src="/s/en_GB/3278/15/_/images/icons/emoticons/error.png" alt="(error)" title="(error)" /> </p></td> </tr> <tr> <td class="confluenceTd"><p> 2.0.0 </p></td> <td class="confluenceTd"><p> < </p></td> <td class="confluenceTd"><p> 2.0-1 </p></td> <td class="confluenceTd"><p> <img class="emoticon emoticon-tick" data-emoticon-name="tick" border="0" src="/s/en_GB/3278/15/_/images/icons/emoticons/check.png" alt="(tick)" title="(tick)" /> </p></td> <td class="confluenceTd"><p> 2.0.0-SNAPSHOT </p></td> <td class="confluenceTd"><p> < </p></td> <td class="confluenceTd"><p> 2.0-1-SNAPSHOT </p></td> <td class="confluenceTd"><p> <img class="emoticon emoticon-cross" data-emoticon-name="cross" border="0" src="/s/en_GB/3278/15/_/images/icons/emoticons/error.png" alt="(error)" title="(error)" /> </p></td> </tr> <tr> <td class="confluenceTd"><p> 2.0-1 </p></td> <td class="confluenceTd"><p> < </p></td> <td class="confluenceTd"><p> 2.0.1 </p></td> <td class="confluenceTd"><p> <img class="emoticon emoticon-tick" data-emoticon-name="tick" border="0" src="/s/en_GB/3278/15/_/images/icons/emoticons/check.png" alt="(tick)" title="(tick)" /> </p></td> <td class="confluenceTd"><p> 2.0-1-SNAPSHOT </p></td> <td class="confluenceTd"><p> < </p></td> <td class="confluenceTd"><p> 2.0.1-SNAPSHOT </p></td> <td class="confluenceTd"><p> <img class="emoticon emoticon-tick" data-emoticon-name="tick" border="0" src="/s/en_GB/3278/15/_/images/icons/emoticons/check.png" alt="(tick)" title="(tick)" /> </p></td> </tr> <tr> <td class="confluenceTd"><p> 2.0.1-klm </p></td> <td class="confluenceTd"><p> < </p></td> <td class="confluenceTd"><p> 2.0.1-lmn </p></td> <td class="confluenceTd"><p> <img class="emoticon emoticon-tick" data-emoticon-name="tick" border="0" src="/s/en_GB/3278/15/_/images/icons/emoticons/check.png" alt="(tick)" title="(tick)" /> </p></td> <td class="confluenceTd"><p> 2.0.1-klm-SNAPSHOT </p></td> <td class="confluenceTd"><p> < </p></td> <td class="confluenceTd"><p> 2.0.1-lmn-SNAPSHOT </p></td> <td class="confluenceTd"><p> <img class="emoticon emoticon-tick" data-emoticon-name="tick" border="0" src="/s/en_GB/3278/15/_/images/icons/emoticons/check.png" alt="(tick)" title="(tick)" /> </p></td> </tr> <tr> <td class="confluenceTd"><p> 2.0.1-xyz </p></td> <td class="confluenceTd"><p> < </p></td> <td class="confluenceTd"><p> 2.0.1 </p></td> <td class="confluenceTd"><p> <img class="emoticon emoticon-tick" data-emoticon-name="tick" border="0" src="/s/en_GB/3278/15/_/images/icons/emoticons/check.png" alt="(tick)" title="(tick)" /> </p></td> <td class="confluenceTd"><p> 2.0.1-xyz-SNAPSHOT </p></td> <td class="confluenceTd"><p> < </p></td> <td class="confluenceTd"><p> 2.0.1-SNAPSHOT </p></td> <td class="confluenceTd"><p> <img class="emoticon emoticon-cross" data-emoticon-name="cross" border="0" src="/s/en_GB/3278/15/_/images/icons/emoticons/error.png" alt="(error)" title="(error)" /> </p></td> </tr> <tr> <td class="confluenceTd"><p> 2.0.1 </p></td> <td class="confluenceTd"><p> < </p></td> <td class="confluenceTd"><p> 2.0.1-123 </p></td> <td class="confluenceTd"><p> <img class="emoticon emoticon-tick" data-emoticon-name="tick" border="0" src="/s/en_GB/3278/15/_/images/icons/emoticons/check.png" alt="(tick)" title="(tick)" /> </p></td> <td class="confluenceTd"><p> 2.0.1-SNAPSHOT </p></td> <td class="confluenceTd"><p> < </p></td> <td class="confluenceTd"><p> 2.0.1-123-SNAPSHOT </p></td> <td class="confluenceTd"><p> <img class="emoticon emoticon-cross" data-emoticon-name="cross" border="0" src="/s/en_GB/3278/15/_/images/icons/emoticons/error.png" alt="(error)" title="(error)" /> </p></td> </tr> <tr> <td class="confluenceTd"><p> 2.0.1-xyz </p></td> <td class="confluenceTd"><p> < </p></td> <td class="confluenceTd"><p> 2.0.1-123 </p></td> <td class="confluenceTd"><p> <img class="emoticon emoticon-tick" data-emoticon-name="tick" border="0" src="/s/en_GB/3278/15/_/images/icons/emoticons/check.png" alt="(tick)" title="(tick)" /> </p></td> <td class="confluenceTd"><p> 2.0.1-xyz-SNAPSHOT </p></td> <td class="confluenceTd"><p> < </p></td> <td class="confluenceTd"><p> 2.0.1-123-SNAPSHOT </p></td> <td class="confluenceTd"><p> <img class="emoticon emoticon-cross" data-emoticon-name="cross" border="0" src="/s/en_GB/3278/15/_/images/icons/emoticons/error.png" alt="(error)" title="(error)" /> </p></td> </tr> </tbody></table> <h3>Proposal</h3> <p>I'm proposing the following implementation: <a href="http://www.neonics.com/~forge/GenericArtifactVersion.java">GenericArtifactVersion.java</a> (unit test: <a href="http://www.neonics.com/~forge/GenericArtifactVersionTest.java">GenericArtifactVersionTest.java</a>). <strong>It has been integrated in artifact 3.0-SNAPSHOT</strong> <strong><a href="http://svn.apache.org/viewvc?rev=656775&view=rev"><strong>r656775</strong></a></strong><strong>(15/5/2008)</strong> <strong>as</strong> <strong><a href="http://svn.apache.org/viewvc/maven/artifact/trunk/src/main/java/org/apache/maven/artifact/versioning/ComparableVersion.java"><strong>ComparableVersion.java</strong></a></strong><strong>.</strong></p> <p>Features:</p> <ul> <li>Mixing of '-' (dash) and '.' (dot) separators</li> <li>Transition between characters and digits also constitutes a separator: <ul> <li>1.0alpha1 => [1, 0, alpha, 1]; This fixes '1.0alpha10 < 1.0alpha2'</li> </ul> </li> <li>Unlimited number of version components</li> <li>Version components in the text can be digits or strings</li> <li>strings are checked for well-known qualifiers and the qualifier ordering is used for version ordering <ul> <li>well-known qualifiers (case insensitive) <ul> <li>snapshot (NOTE; snapshot needs discussion)</li> <li>alpha or a</li> <li>beta or b</li> <li>milestone or m</li> <li>rc or cr</li> <li>(the empty string) or ga or final</li> <li>sp</li> </ul> </li> </ul> </li> <li>version components prefixed with '-' will result in a sub-list of version components. <br class="atl-forced-newline" /> A dash usually precedes a qualifier, and is always less important than something preceded with a dot. <br class="atl-forced-newline" /> We need to somehow record the separators themselves, which is done by sublists. <br class="atl-forced-newline" /> Parse examples: <ul> <li>1.0-alpha1 => [1, 0, ["alpha", 1]]</li> <li>1.0-rc-2 => [1, 0, ["rc", [2]]]</li> </ul> </li> </ul> <h4>Parsing versions</h4> <p>The version string is examined one character at a time.<br /> There's a buffer containing the current text - all characters are appended, except for '.' and '-'.<br /> Below, when it's stated 'append buffer to list', the buffer is first converted to an Integer item if that's possible, otherwise left alone as a String. It will only be appended if it's length is not 0.</p> <ul> <li>If a '.' is encountered, the current buffer is appended to the current list, either as a IntegerItem (if it's a number) or a StringItem.</li> <li>If a '-' is encountered, do the same as when a '.' is encountered, then create a new sublist, append it to the current list and replace the current list with the new sub-list.</li> <li>If the last character was a digit: <ul> <li>and the current one is too, append it to the buffer.</li> <li>otherwise append the current buffer to the list, reset the buffer with the current char as content</li> </ul> </li> <li>if the last character was NOT a digit: <ul> <li>if the last character was also NOT a digit, append it to the buffer</li> <li>if it is a digit, append buffer to list, set buffers content to the digit</li> </ul> </li> <li>finally, append the buffer to the list</li> </ul> <p>Some examples:</p> <ul> <li>1.0 => [1, 0]</li> <li>1.0.1 => [1, 0, 1]</li> <li>1-SNAPSHOT => [1, ["SNAPSHOT"]]</li> <li>1-alpha10-SNAPSHOT => [1, ["alpha", "10", ["SNAPSHOT"]]]</li> </ul> <h3>Ordering algorithm</h3> <p>Internally 3 version component types are used:</p> <ul> <li>integer (IntegerItem)</li> <li>string (StringItem) (knows if it's a qualifier or not)</li> <li>sublist (ListItem)</li> </ul> <p>Elements from both versions are compared one at a time; first the first element of both, then the second, etc.</p> <p>(Note: 'item' and 'component' are used interchangeably)</p> <p>ordering rules when comparing version components:</p> <table class="confluenceTable"><tbody> <tr> <th class="confluenceTh"><p> </p></th> <th class="confluenceTh"><p> Integer </p></th> <th class="confluenceTh"><p> String </p></th> <th class="confluenceTh"><p> List </p></th> <th class="confluenceTh"><p> null </p></th> </tr> <tr> <th class="confluenceTh"><p> Integer </p></th> <td class="confluenceTd"><p> Highest is newer </p></td> <td class="confluenceTd"><p> Integer is newer </p></td> <td class="confluenceTd"><p> Integer is newer </p></td> <td class="confluenceTd"><p> If integer==0 then equal, <br class="atl-forced-newline" /> otherwise integer is newer </p></td> </tr> <tr> <th class="confluenceTh"><p> String </p></th> <td class="confluenceTd"><p> Integer is newer </p></td> <td class="confluenceTd"><p> order by well-known <br class="atl-forced-newline" /> qualifiers and lexically <br class="atl-forced-newline" /> (see below) </p></td> <td class="confluenceTd"><p> List is newer </p></td> <td class="confluenceTd"><p> Compare with "" <br class="atl-forced-newline" /> </p></td> </tr> <tr> <th class="confluenceTh"><p> List </p></th> <td class="confluenceTd"><p> Integer is newer </p></td> <td class="confluenceTd"><p> List is newer </p></td> <td class="confluenceTd"><p> Version itself is a list; compare item by item </p></td> <td class="confluenceTd"><p> Compare with empty list item (recursion) <br class="atl-forced-newline" /> this will finally result in String==?null or <br class="atl-forced-newline" /> Integer==?null </p></td> </tr> <tr> <th class="confluenceTh"><p> null </p></th> <td class="confluenceTd"><p> If integer==0 then equal, <br class="atl-forced-newline" /> otherwise integer is newer </p></td> <td class="confluenceTd"><p> Compare with "" </p></td> <td class="confluenceTd"><p> Compare with empty list item (recursion) <br class="atl-forced-newline" /> this will finally result in String==?null or <br class="atl-forced-newline" /> Integer==?null </p></td> <td class="confluenceTd"><p> doesn't happen </p></td> </tr> </tbody></table> <p>Special note on string comparing:<br /> A predefined list of well-known qualifiers is present. For comparison, the string is converted to another string, as follows:</p> <ul> <li>First, the well-known qualifier list is consulted for presence of the string</li> <li>If the string is present, the index in the list is returned, as a string</li> <li>If the string is not present, then qualifiers.size() + "-" + string is returned.</li> </ul> <p>Then the strings are lexically compared.</p> <p>Examples:</p> <ul> <li>"alpha" yields "1"</li> <li>"" yields "4"</li> <li>"abc" yields "7-abc"</li> <li>"xyz" yields "7-xyz"</li> </ul> <p>String Compare examples:</p> <ul> <li>1.0 ==? 1.0-alpha: "" (or null) ==? "alpha" -> "4" ==? "1" -> 1.0 is newer</li> <li>1 ==? 1.0: equal</li> <li>1-beta ==? 1-xyz: "2" ==? "7-xyz" -> 1-xyz is newer</li> </ul> <p>Some comparisons that yield different results from the current implementation:</p> <ul> <li>1-beta ==? 1-abc: "2" ==? "7-abc" -> 1-abc is newer</li> <li>1.0 ==? 1.0-abc: "4" ==? "7-abc" -> 1.0-abc is newer</li> <li>1.0-alpha-10 ==? 1.0-alpha-2: 10 > 2, so '1.0-alpha-10' is newer</li> <li>1.0-alpha-1.0 ==? 1.0-alpha-1: equal</li> <li>1.0-alpha-1.2 ==? 1.0-alpha-2: 1.0-alpha-2 is newer</li> </ul> <p>Note: This approach differs from the version comparison as done by OSGi <a class="confluence-link" href="#osgi" data-anchor="osgi" data-linked-resource-default-alias="osgi" data-base-url="http://docs.codehaus.org">[0]</a>.</p> <h1>Make version handling pluggable</h1> <p>When somebody devices a version scheme that cannot be handled by the above, it should be possible to plug in a new scheme. Two possible scenarios for unsupported schemes:</p> <ul> <li>The dash hash higher priority than the dot: 1-0 is newer than 1.0</li> <li>Dashes and dots have the same priority: 1.1 == 1-1.</li> <li>Qualifier order is different, or unknown qualifiers.</li> </ul> <p>To make version schemes pluggable, the following is required:</p> <ul> <li>A POM change to support something like this to identify a version-scheme implementation artifact: <br class="atl-forced-newline" /> <table class="wysiwyg-macro" data-macro-name="noformat" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e25vZm9ybWF0fQ&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre><versionScheme> <groupId>..</groupId> <artifactId>..</artifactId> <version>..</version> <\!-\- we may need to disallow version ranges here \--> </versionScheme> </pre></td></tr></table> <br class="atl-forced-newline" /></li> <li>Maven-metadata at the artifact level needs to include the tag above. We'll limit version schemes on a per artifact basis. This is required in order to resolve versions using ranges.</li> <li>An interface definition for VersionScheme</li> <li>A way to detect what is the version class inside the version-scheme artifact; I hope we can use plexus, as long as multiple version-scheme implementations (same hint, same package/classname) can be accessed simultaneously without conflict.</li> <li>Refactoring the version code out of maven-artifact so plugin code etc. can use it too</li> <li>The super pom will contain a default versionScheme tag listing the maven internal implementation</li> </ul> <h2>Define a grammar for version specifications</h2> <p>I'm not entirely sure this is necessary, but for other languages that cannot use pre-packaged version scheme implementations in Java, we need to have some sort of metadata, preferrably in the version-scheme artifact, describing the version scheme. Perhaps something like version-scheme-1.0.jar!/META-INF/maven/version-scheme.file-extension </p> <p>Several proposals have been made for the version scheme description language:</p> <ul> <li>regular expressions. Downside: you cannot record version ordering information, only parse rules</li> <li>(E)BNF grammar. Same downside, though the operator ('.' and '-') priority can be expressed by the level in the AST.</li> <li>XSD.</li> <li>XML, where we provide an XSD with the grammar for the grammar.</li> </ul> <p>As an example here's an XSD you could use to describe versions: <br class="atl-forced-newline" /></p> <table class="wysiwyg-macro" data-macro-name="noformat" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e25vZm9ybWF0fQ&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre><xs:schema> <xs:element name="versionSchemeDefinition"> <xs:complexType> <xs:sequence> <!-- the order of qualifierDefinitions is from oldest to newest --> <xs:element ref="qualifierDefinition" minOccurs="0" maxOccurs="unbounded"/> <xs:choice maxOccurs="unbounded" minOccurs="0"> <xs:element ref="stringComponent"/> <xs:element ref="numberComponent"/> <xs:element ref="subComponent"/> </xs:choice> </xs:sequence> </xs:complexType> </xs:element> <xs:element name="qualifierDefinition"> <xs:complexType> <xs:attribute name="name" type="xs:string"/> <xs:attribute name="caseSensitive" type="xs:boolean" default="false"/> </xs:complexType> </xs:element> <xs:element name="stringComponent"> <xs:complexType> <xs:attribute name="name" type="xs:string"/> <xs:attribute name="prefix" type="xs:string" default="."/> </xs:complexType> </xs:element> <xs:element name="numberComponent" type="xs:int"> <xs:complexType> <xs:attribute name="name" type="xs:string"/> <xs:attribute name="prefix" type="xs:string" default="."/> <xs:attribute name="optional" type="xs:boolean" default="false"/> </xs:complexType> </xs:element> <xs:element name="subComponent"> <xs:complexType> <xs:choice maxOccurs="unbounded" minOccurs="0"> <xs:element ref="stringComponent"/> <xs:element ref="numberComponent"/> <xs:element ref="subComponent"/> </xs:choice> <xs:attribute name="name" type="xs:string"/> <xs:attribute name="prefix" type="xs:string" default="-"/> </xs:complexType> </xs:element> </xs:schema> </pre></td></tr></table> <p><br class="atl-forced-newline" /> A sample scheme:</p> <table class="wysiwyg-macro" data-macro-name="noformat" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e25vZm9ybWF0fQ&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre><versionSchemeDefinition> <qualifierDefinition name="snapshot"/> <qualifierDefinition name="alpha"/> <qualifierDefinition name="beta"/> <qualifierDefinition name="rc"/> <qualifierDefinition name=""/> <qualifierDefinition name="ga"/> <qualifierDefinition name="sp"/> <numberComponent name="major"/> <numberComponent name="minor" optional="true"/> <numberComponent name="micro" optional="true"/> <stringComponent name="qualifier" optional="true"/> <numberComponent name="buildnumber" optional="true"/> </versionSchemeDefinition> </pre></td></tr></table> <p><br class="atl-forced-newline" /> This scheme doesn't even come close to being able to describe the variety of version schemes supported by my proposal.<br /> Perhaps it's better if, when we do XML, we use XSD to describe the version schemes.<br /> We define a set of simple/complextypes that people have to extend, and the engine can then convert it to a parser/verifier/order implementation/representation using the base classes.<br /> The parser would use the 'prefix' values and the type attributes to determine what kind of token is next, in the version string. It would then build an XML DOM that can be validated against the XSD, which can have extra rules.<br /> Anyway, UDDI tried to do something similar for random applications - to have the API specs in a uniform format so you could generate an application around reusable components, but that didn't work out and AFAIK the specs are just human readable documents. If somebody wants to create a parser/validator/sorter for a version spec, there should just be enough documentation for them to do it. <br class="atl-forced-newline" /> <br class="atl-forced-newline" /> <br class="atl-forced-newline" /> <br class="atl-forced-newline" /> <br class="atl-forced-newline" /> <br class="atl-forced-newline" /></p> <h2>References and Related Material</h2> <p><img class="editor-inline-macro" src="/plugins/servlet/confluence/placeholder/macro?definition=e2FuY2hvcjpvc2dpfQ&locale=en_GB&version=2" data-macro-name="anchor" data-macro-default-parameter="osgi"> [0] <a href="http://www.osgi.org/Release4/Download">OSGi Service Platform Release 4 Version 4.1 Core Specification</a>, §3.2.4 "Version" and §3.2.5 "Version Ranges" on page 38, §3.5.3 "Bundle-Version" on page 46, §6.1.26.5 "Version.compareTo()" on page 200</p>
Please type the word appearing in the picture.
Attachments
Labels
Location
Watch this page
< Edit
Preview >
Loading…
Save
Cancel
Next hint
search
attachments
weblink
advanced