From 17a2f5a2ba81fafe08146f0b6dbc98e6d292d259 Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Sat, 25 Jul 2026 00:58:53 +0200 Subject: [PATCH 1/2] chore: enable Maven 4 build and fix embedded-mode IT failures Enable Maven 4 in the CI matrix by setting maven4-enabled: true. Exclude JDK 11 from Maven 4 cells since Maven 4 requires Java 17+ (JDK 8 is already auto-excluded by the shared workflow). Force forked JVM mode in MavenLauncher when Maven 4 is detected, working around maven-verifier 2.0.0-M1's broken embedded-mode reflection against the changed MavenCling.doMain() signature in Maven 4 rc-5. Detection checks for maven-cling-*.jar in the Maven home lib directory. This workaround can be removed once surefire migrates from maven-verifier to maven-executor. Also fix a pre-existing race condition in CountdownCloseable where awaitClosed() used 'if' instead of 'while' to guard Object.wait(), making it vulnerable to spurious wakeups per the JLS. Co-Authored-By: Claude Opus 4.6 --- .github/workflows/maven-verify.yml | 4 +++ .../extensions/util/CountdownCloseable.java | 2 +- .../surefire/its/fixture/MavenLauncher.java | 32 +++++++++++++++++-- 3 files changed, 35 insertions(+), 3 deletions(-) diff --git a/.github/workflows/maven-verify.yml b/.github/workflows/maven-verify.yml index 2d827a276a..fd9b059062 100644 --- a/.github/workflows/maven-verify.yml +++ b/.github/workflows/maven-verify.yml @@ -50,3 +50,7 @@ jobs: !surefire-its/target/ConsoleOutputIT_*/target/surefire-reports/*-jvmRun*-events.bin timeout-minutes: 600 os-matrix: '[ "ubuntu-latest", "windows-latest", "macos-latest" ]' + maven4-enabled: true + matrix-exclude: '[ + { "jdk": "11", "maven": "4.0.0-rc-5" } + ]' diff --git a/surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/util/CountdownCloseable.java b/surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/util/CountdownCloseable.java index 02f7846dfd..d0dbafda9f 100644 --- a/surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/util/CountdownCloseable.java +++ b/surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/util/CountdownCloseable.java @@ -53,7 +53,7 @@ public synchronized void close() throws IOException { * @throws InterruptedException see {@link Object#wait()} */ public synchronized void awaitClosed() throws InterruptedException { - if (countdown > 0) { + while (countdown > 0) { wait(); } } diff --git a/surefire-its/src/test/java/org/apache/maven/surefire/its/fixture/MavenLauncher.java b/surefire-its/src/test/java/org/apache/maven/surefire/its/fixture/MavenLauncher.java index 463d8b46e7..4f01c11602 100755 --- a/surefire-its/src/test/java/org/apache/maven/surefire/its/fixture/MavenLauncher.java +++ b/surefire-its/src/test/java/org/apache/maven/surefire/its/fixture/MavenLauncher.java @@ -76,8 +76,10 @@ public final class MavenLauncher { this.resourceName = resourceName; this.suffix = suffix != null ? suffix : ""; this.cli = cli == null ? null : cli.clone(); - // by default use embedded mode - this.forkJvm = false; + // Use forked mode for Maven 4+ because maven-verifier 2.0.0-M1's embedded mode + // uses reflection against MavenCling.doMain() with an incompatible method signature. + // Once surefire migrates from maven-verifier to maven-executor, this can be removed. + this.forkJvm = isMaven4(); resetGoals(); resetCliOptions(); } @@ -409,6 +411,32 @@ private static Verifier createVerifier(String basedir, String settingsFile, Stri : new Verifier(basedir, settingsFile, false, defaultCliOptions); } + /** + * Detects if the current Maven installation is version 4.x or later by checking for the + * presence of {@code maven-cling-*.jar} in the Maven home lib directory. Maven 4 introduced + * the {@code maven-cling} module which is not present in Maven 3.x installations. + * + * @return {@code true} if Maven 4+ is detected + */ + private static boolean isMaven4() { + String mavenHome = System.getProperty("maven.home", ""); + if (mavenHome.isEmpty()) { + return false; + } + File libDir = new File(mavenHome, "lib"); + if (libDir.isDirectory()) { + String[] files = libDir.list(); + if (files != null) { + for (String file : files) { + if (file.startsWith("maven-cling-")) { + return true; + } + } + } + } + return false; + } + private static File settingsXmlPath() { try { return new File(System.getProperty("maven.settings.file")).getCanonicalFile(); From b67bf233ea3fe2af5512d2d57b6250180ee6ffd8 Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Sat, 25 Jul 2026 01:19:53 +0200 Subject: [PATCH 2/2] fix: detect Maven 4 via maven-cli jar instead of maven-cling The Maven 4 distribution does not contain a separate maven-cling jar. The MavenCling class is inside maven-cli-4.x.jar, which is a Maven 4-only artifact not present in Maven 3.x distributions. Co-Authored-By: Claude Opus 4.6 --- .../apache/maven/surefire/its/fixture/MavenLauncher.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/surefire-its/src/test/java/org/apache/maven/surefire/its/fixture/MavenLauncher.java b/surefire-its/src/test/java/org/apache/maven/surefire/its/fixture/MavenLauncher.java index 4f01c11602..e10a16bd6d 100755 --- a/surefire-its/src/test/java/org/apache/maven/surefire/its/fixture/MavenLauncher.java +++ b/surefire-its/src/test/java/org/apache/maven/surefire/its/fixture/MavenLauncher.java @@ -413,8 +413,8 @@ private static Verifier createVerifier(String basedir, String settingsFile, Stri /** * Detects if the current Maven installation is version 4.x or later by checking for the - * presence of {@code maven-cling-*.jar} in the Maven home lib directory. Maven 4 introduced - * the {@code maven-cling} module which is not present in Maven 3.x installations. + * presence of {@code maven-cli-*.jar} in the Maven home lib directory. Maven 4 introduced + * the {@code maven-cli} module which is not present in Maven 3.x installations. * * @return {@code true} if Maven 4+ is detected */ @@ -428,7 +428,7 @@ private static boolean isMaven4() { String[] files = libDir.list(); if (files != null) { for (String file : files) { - if (file.startsWith("maven-cling-")) { + if (file.startsWith("maven-cli-")) { return true; } }