This is an automated email from the ASF dual-hosted git repository.
cstamas pushed a commit to branch maven-resolver-1.9.x
in repository https://gitbox.apache.org/repos/asf/maven-resolver.git
The following commit(s) were added to refs/heads/maven-resolver-1.9.x by this
push:
new 24dd0e041 [MRESOLVER-686] Backport index==0 kind-mismatch fix to 1.9.x
(#1852)
24dd0e041 is described below
commit 24dd0e04139bbdd440472f14de8da2ee2b8cf2e8
Author: Ben Tatham <[email protected]>
AuthorDate: Mon Jun 15 14:55:29 2026 -0400
[MRESOLVER-686] Backport index==0 kind-mismatch fix to 1.9.x (#1852)
When two versions differ in kind at index 0 (e.g. a string-prefixed
branch-style version versus a numeric release whose first segment is
zero), comparePadding with a number filter may return 0 even though the
versions are clearly different. That makes equality non-transitive and
breaks TimSort when DefaultVersionRangeResolver sorts metadata lists
mixing both shapes.
This is the same fix as MRESOLVER-336, which was applied to 2.x but
never landed on the 1.9.x line that ships with Maven 3.9.x.
Adds two regression tests covering the three-way transitivity violation
and a representative sort.
---
.../aether/util/version/GenericVersion.java | 3 +
.../aether/util/version/GenericVersionTest.java | 78 ++++++++++++++++++++++
2 files changed, 81 insertions(+)
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 fc90ae270..4cb2863ad 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
@@ -122,6 +122,9 @@ final class GenericVersion implements Version {
Item thatItem = those.get(index);
if (thisItem.isNumber() != thatItem.isNumber()) {
+ if (index == 0) {
+ return thisItem.compareTo(thatItem);
+ }
if (number == thisItem.isNumber()) {
return comparePadding(these, index, number);
} else {
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 79543547d..71d72beab 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,7 +19,9 @@
package org.eclipse.aether.util.version;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
+import java.util.List;
import java.util.Locale;
import java.util.UUID;
import java.util.stream.Collectors;
@@ -29,6 +31,8 @@ import org.eclipse.aether.version.Version;
import org.junit.Test;
import static java.util.stream.Collectors.toList;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
/**
@@ -380,6 +384,80 @@ public class GenericVersionTest extends
AbstractVersionTest {
uuidVersionStringStream().map(this::newVersion).sorted().collect(toList());
}
+ /**
+ * UT for <a
href="https://issues.apache.org/jira/browse/MRESOLVER-686">MRESOLVER-686</a>.
+ *
+ * When two versions differ in kind at index 0 (e.g. a string-prefixed
branch-style version versus a numeric
+ * release whose first segment happens to be zero), comparePadding with a
number filter may return 0 even though
+ * the versions are clearly different. That makes equality non-transitive
and breaks TimSort when Maven's
+ * DefaultVersionRangeResolver sorts a metadata list mixing both shapes.
+ */
+ @Test
+ public void testTransitivityAtIndexZeroKindMismatch() {
+ Version a = newVersion("foo-branch-SNAPSHOT");
+ Version b = newVersion("0-x-SNAPSHOT");
+ Version c = newVersion("zar-branch-SNAPSHOT");
+
+ int ab = Integer.signum(a.compareTo(b));
+ int bc = Integer.signum(b.compareTo(c));
+ int ac = Integer.signum(a.compareTo(c));
+ // With the fix, at index 0 the kind difference (STRING(3) < INT(4))
wins: a < b and c < b.
+ assertOrder(X_LT_Y, "foo-branch-SNAPSHOT", "0-x-SNAPSHOT");
+ assertOrder(X_LT_Y, "zar-branch-SNAPSHOT", "0-x-SNAPSHOT");
+ assertOrder(X_LT_Y, "foo-branch-SNAPSHOT", "zar-branch-SNAPSHOT");
+ // and the three results must be transitively consistent
+ if (ab == 0 && bc == 0 && ac != 0) {
+ fail("equality is not transitive: a~b~c but a!=c");
+ }
+ }
+
+ /**
+ * UT for <a
href="https://issues.apache.org/jira/browse/MRESOLVER-686">MRESOLVER-686</a>.
+ *
+ * Sorting a representative mix of string-prefixed branch-style SNAPSHOT
names and numeric releases (the kind of
+ * list Maven's DefaultVersionRangeResolver builds from a repository's
maven-metadata.xml) must not throw
+ * {@code IllegalArgumentException}, must produce a non-decreasing
sequence under {@link Version#compareTo}, and
+ * must place every string-prefixed version before every numeric-prefixed
version (kind at index 0 wins).
+ */
+ @Test
+ public void testSortBranchAndNumericVersions() {
+ List<String> input = Arrays.asList(
+ "foo-branch-1-SNAPSHOT",
+ "bar-branch-2-SNAPSHOT",
+ "baz-branch-3-SNAPSHOT",
+ "qux-branch-4-SNAPSHOT",
+ "quux-branch-5-SNAPSHOT",
+ "corge-branch-6-SNAPSHOT",
+ "garply-branch-7-SNAPSHOT",
+ "waldo-branch-8-SNAPSHOT",
+ "0-latest-SNAPSHOT",
+ "0.0-SNAPSHOT",
+ "0.5640-SNAPSHOT",
+ "0.5641-SNAPSHOT",
+ "1.163.0.0-qa",
+ "2.19.0.0-dev",
+ "2.19.0.0-qa",
+ "3.59.0.0-dev",
+ "4.225.2.0-dev",
+ "4.225.2.1-dev");
+ List<Version> sorted =
input.stream().map(this::newVersion).sorted().collect(toList());
+
+ // Sort is total: no element lost or duplicated.
+ assertEquals(input.size(), sorted.size());
+
+ // Sorted output is non-decreasing under compareTo (sanity-checks the
comparator itself).
+ for (int i = 0; i + 1 < sorted.size(); i++) {
+ assertTrue(
+ "sorted[" + i + "]=" + sorted.get(i) + " should be <=
sorted[" + (i + 1) + "]=" + sorted.get(i + 1),
+ sorted.get(i).compareTo(sorted.get(i + 1)) <= 0);
+ }
+
+ // All string-prefixed entries must sort before all numeric-prefixed
entries, and the specific
+ // highest / lowest elements are what we expect.
+ assertEquals("bar-branch-2-SNAPSHOT", sorted.get(0).toString());
+ assertEquals("4.225.2.1-dev", sorted.get(sorted.size() -
1).toString());
+ }
+
private Stream<String> uuidVersionStringStream() {
return Stream.of(
"e3f6b227-e09d-4461-a030-b8c1755834f7",