You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by cs...@apache.org on 2023/02/17 08:17:43 UTC

[maven-resolver] branch master updated: [MRESOLVER-314] IAEx thrown when sorting versions with hex values (#249)

This is an automated email from the ASF dual-hosted git repository.

cstamas pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven-resolver.git


The following commit(s) were added to refs/heads/master by this push:
     new d731dc44 [MRESOLVER-314] IAEx thrown when sorting versions with hex values (#249)
d731dc44 is described below

commit d731dc44c5cf3950846dc4cd055b0beda63928aa
Author: Tamas Cservenak <ta...@cservenak.net>
AuthorDate: Fri Feb 17 09:17:38 2023 +0100

    [MRESOLVER-314] IAEx thrown when sorting versions with hex values (#249)
    
    Long outstanding problem: GenericVersion since long time had issue with sorting some peculiar version strings (well, parsing them and the producing comparable Version instances to be precise). One kind of these peculiar strings are hex strings, that we even encourage should be used on this page https://maven.apache.org/maven-ci-friendly.html Problems happen, when Maven decides to sort these versions, like it happened to user using `versions-maven-plugin:set-property` that involves ver [...]
    
    Origin of the problem is that GenericVersion instances, when parsed out of hex-like strings, produce instances that violate Comparable contract (comparison is transitive), hence Java throws `Caused by: java.lang.IllegalArgumentException: Comparison method violates its general contract!` just out of the blue. Moreover, this problem affects both set of users: those who produce hex-like versioned artifacts, but also those who consume them.
    
    Problem was compare padding: when a number and non-number was about to be compared, the comparePadding was invoked, that simply stopped when a number was followed by a non-number. Proper fix is to make iteration all way to the end, otherwise here we end up with compare result 0 that means "equals", which in fact is not.
    
    ---
    
    https://issues.apache.org/jira/browse/MRESOLVER-314
---
 .../aether/util/version/GenericVersion.java        |  13 ++-
 .../aether/util/version/GenericVersionTest.java    | 125 ++++++++++++++++++++-
 2 files changed, 132 insertions(+), 6 deletions(-)

diff --git a/maven-resolver-util/src/main/java/org/eclipse/aether/util/version/GenericVersion.java b/maven-resolver-util/src/main/java/org/eclipse/aether/util/version/GenericVersion.java
index 10219185..b440dbc9 100644
--- a/maven-resolver-util/src/main/java/org/eclipse/aether/util/version/GenericVersion.java
+++ b/maven-resolver-util/src/main/java/org/eclipse/aether/util/version/GenericVersion.java
@@ -170,7 +170,8 @@ final class GenericVersion
             Item item = items.get( i );
             if ( number != null && number != item.isNumber() )
             {
-                break;
+                // do not stop here, but continue, skipping non-number members
+                continue;
             }
             rel = item.compareTo( null );
             if ( rel != 0 )
@@ -228,6 +229,8 @@ final class GenericVersion
 
         private final String version;
 
+        private final int versionLength;
+
         private int index;
 
         private String token;
@@ -239,12 +242,12 @@ final class GenericVersion
         Tokenizer( String version )
         {
             this.version = ( version.length() > 0 ) ? version : "0";
+            this.versionLength = this.version.length();
         }
 
         public boolean next()
         {
-            final int n = version.length();
-            if ( index >= n )
+            if ( index >= versionLength )
             {
                 return false;
             }
@@ -252,10 +255,10 @@ final class GenericVersion
             int state = -2;
 
             int start = index;
-            int end = n;
+            int end = versionLength;
             terminatedByNumber = false;
 
-            for ( ; index < n; index++ )
+            for ( ; index < versionLength; index++ )
             {
                 char c = version.charAt( index );
 
diff --git a/maven-resolver-util/src/test/java/org/eclipse/aether/util/version/GenericVersionTest.java b/maven-resolver-util/src/test/java/org/eclipse/aether/util/version/GenericVersionTest.java
index 8d058e44..55fbc8c3 100644
--- a/maven-resolver-util/src/test/java/org/eclipse/aether/util/version/GenericVersionTest.java
+++ b/maven-resolver-util/src/test/java/org/eclipse/aether/util/version/GenericVersionTest.java
@@ -19,12 +19,19 @@ package org.eclipse.aether.util.version;
  * under the License.
  */
 
+import java.util.ArrayList;
+import java.util.Collections;
 import java.util.Locale;
+import java.util.UUID;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
-import org.eclipse.aether.util.version.GenericVersion;
 import org.eclipse.aether.version.Version;
 import org.junit.Test;
 
+import static java.util.stream.Collectors.toList;
+import static org.junit.Assert.fail;
+
 /**
  */
 public class GenericVersionTest
@@ -345,4 +352,120 @@ public class GenericVersionTest
         assertOrder( X_LT_Y, "1.max", "2.min" );
     }
 
+    /**
+     * UT for <a href="https://issues.apache.org/jira/browse/MRESOLVER-314">MRESOLVER-314</a>.
+     *
+     * Generates random UUID string based versions and tries to sort them. While this test is not as reliable
+     * as {@link #testCompareUuidVersionStringStream()}, it covers broader range and in case it fails it records
+     * the failed array, so we can investigate more.
+     */
+    @Test
+    public void testCompareUuidRandom() {
+            for ( int j = 0; j < 32; j++ )
+            {
+                ArrayList<Version> versions = new ArrayList<>();
+                for ( int i = 0; i < 64; i++ )
+                {
+                    versions.add( newVersion( UUID.randomUUID().toString() ) );
+                }
+                try
+                {
+                    Collections.sort( versions );
+                }
+                catch ( Exception e )
+                {
+                    e.printStackTrace( System.err );
+                    System.err.println( "The UUIDs used" );
+                    System.err.println(
+                            versions.stream().map( Version::toString ).collect( Collectors.joining( "\n" ) ) );
+                    fail( "unexpected exception" );
+                }
+            }
+    }
+
+    /**
+     * UT for <a href="https://issues.apache.org/jira/browse/MRESOLVER-314">MRESOLVER-314</a>.
+     *
+     * Works on known set that failed before fix, provided by {@link #uuidVersionStringStream()}.
+     */
+    @Test
+    public void testCompareUuidVersionStringStream()
+    {
+        // this operation below fails with IAEx if comparison is unstable
+        uuidVersionStringStream()
+                .map( this::newVersion )
+                .sorted()
+                .collect( toList() );
+    }
+
+    private Stream<String> uuidVersionStringStream()
+    {
+        return Stream.of(
+                "e3f6b227-e09d-4461-a030-b8c1755834f7",
+                "dfdf5e15-b047-4fee-94e5-3ddf6fe90a0c",
+                "bcc15412-6817-4b64-acef-169d048626f6",
+                "76093f07-ab1c-4cdd-ae92-9bb500ceed84",
+                "7ca8dc9f-4e73-459b-8f30-06aa7972f486",
+                "93fee46b-2715-4abd-877a-4197eb8601aa",
+                "0379da36-84ee-4d06-9388-83d3aa6536b5",
+                "4bb2c7a8-cf68-4ca5-8024-72dc93506da9",
+                "9dcc4cd1-34d2-4499-8dab-3ef8bca9680d",
+                "ea53d552-83ab-4f7d-852d-98951201083d",
+                "0bc420d2-4089-468b-bc54-0a4e2835feed",
+                "318d2433-fe40-4f28-9f3a-4e3d66d9b5fb",
+                "447b456c-81a4-4f24-9d2e-e5091c39cd19",
+                "85741f6e-26fe-40d0-a73a-283315409ab2",
+                "3165b9b2-9f8e-4117-ac70-87056eb45745",
+                "9d534bf3-a3b0-4a19-9809-670934c10752",
+                "86d78bba-d84e-4349-aea6-850721e78188",
+                "06392b8c-e26c-4a83-8ec2-085415bc513d",
+                "1fb13754-90be-42cb-bc7f-9b9211494e92",
+                "3018965c-3330-402a-8075-caa7613ec4fa",
+                "7ecc912b-4938-4411-895e-8ca7cf22ce02",
+                "6580ada2-4764-45a2-9789-98217d7cf5b6",
+                "be9d0de4-4ba7-4fdd-8f76-cb579168c549",
+                "7a8236d6-6bec-4176-b6a1-f869c02183c3",
+                "089f4195-881c-4f9e-8bc1-124531dee977",
+                "46ffda62-768a-4864-9581-cc75eafe1a67",
+                "1d6226f6-dacc-42a9-bd88-7aab1f59df74",
+                "0948ed55-c25e-4319-9801-5f817bac09b5",
+                "2fd52f5e-b856-47ad-9e58-45c1d0ba437b",
+                "6c325bd0-ac6b-4391-a5c5-caa160972fa2",
+                "d213f6be-f56b-42d2-abda-4300742e0add",
+                "efaae115-cc21-4b2e-a150-fb4e0d807736",
+                "30f872e8-9cb5-4b22-b65c-6819ca7a14ba",
+                "d8e5fb54-6e90-4f74-adb3-451abfbe76a8",
+                "b47d62b8-9256-47a1-8e21-21ba9639c212",
+                "b25da555-e1f7-4bc5-92fe-4c895d9c70d8",
+                "088f0de7-5973-4c10-a7ff-9f3cd7718572",
+                "b161de76-e5d5-4224-883b-a749b147d63d",
+                "19b7de96-09fa-4276-843d-c0fbdaf07767",
+                "e0503f73-33fd-4f9c-812f-8cae3a128c28",
+                "b8c57488-a42c-43ed-bfb9-acd112d6b68f",
+                "25997299-0825-4c9b-b0ed-75f935c63fd7",
+                "2b2e2fcd-3988-45af-855b-7646c0cdbfb5",
+                "4e6e16b9-2ae4-4593-b907-1febaf3988dc",
+                "ac8bd519-7fd4-4b85-8154-9dbb87f6cd4f",
+                "61473b39-b620-468b-abcf-16fe6adfd5cb",
+                "18e7a548-3f0b-492b-bc19-dce3eec736fa",
+                "c4d82839-3c46-4eff-b10c-ec0b5bcc600b",
+                "48f6e90f-924b-4859-9763-3ffe661f5af6",
+                "48852d79-ba23-475e-b675-a413b989a2a7",
+                "f7ee0915-ff00-4404-9e9a-6e753d5ff767",
+                "d6462359-a4e2-45ab-aedc-3b1849b0e6ca",
+                "e66228de-d1ed-4973-a108-c181d5059fdb",
+                "d49672a7-177d-475d-aad0-aab0ff4a11b7",
+                "bfa9337a-0489-4cba-b2db-e0d9d2424e4f",
+                "dc9bbe34-3c54-4c0f-a3cd-00e96604ae23",
+                "a8119cf1-9694-4b24-923a-3fc729b5f809",
+                "5d29cf45-3b9c-4697-85b8-86c81c6ec0c9",
+                "e3dcb4c2-a867-40f7-a3b1-fb1058a041e5",
+                "ae240754-2ea2-409a-a92c-648fc7a7b70b",
+                "8c187383-d59b-4e49-8dfd-98aa5f01925a",
+                "9b100ee6-71ed-4746-92c2-b5fb02af7ebd",
+                "f95e94f7-2443-4b2f-a10d-059d8d224dd9",
+                "b558af80-78bc-43c7-b916-d635a23cc4b5");
+    }
+
+
 }