Apache Maven Verifier is deprecated and will be replaced by maven-executor.
New projects should use maven-executor. Existing projects should plan migration to maven-executor.
See Issue #186 for more details.
Maven currently has two overlapping components for running Maven programmatically:
Both have issues:
Remove:
<dependency> <groupId>org.apache.maven.shared</groupId> <artifactId>maven-verifier</artifactId> <scope>test</scope> </dependency>
Add:
<dependency> <groupId>org.apache.maven</groupId> <artifactId>maven-executor</artifactId> <version>4.0.0-rc-5</version> <!-- Use latest version --> <scope>test</scope> </dependency>
Note: maven-executor location may change as it might be moved out of Maven 4 core to become a standalone project. Check the latest documentation.
import org.apache.maven.shared.verifier.Verifier; import org.apache.maven.shared.verifier.VerificationException; public class MyTest { @Test public void testBuild() throws Exception { String baseDir = "/path/to/project"; Verifier verifier = new Verifier(baseDir); // Configure verifier.setAutoclean(false); verifier.setMavenDebug(true); verifier.addCliArgument("-DskipTests=true"); // Execute verifier.addCliArgument("package"); verifier.execute(); // Verify verifier.verifyErrorFreeLog(); verifier.verifyFilePresent("target/my-app-1.0.jar"); verifier.resetStreams(); } }
import org.apache.maven.api.cli.Executor; import org.apache.maven.api.cli.ExecutorRequest; import org.apache.maven.cling.executor.forked.ForkedExecutor; import org.apache.maven.cling.executor.embedded.EmbeddedExecutor; import java.nio.file.Path; import java.nio.file.Paths; import java.util.Arrays; public class MyTest { @Test public void testBuild() throws Exception { Path baseDir = Paths.get("/path/to/project"); // Choose executor type: Forked or Embedded Executor executor = new ForkedExecutor(); // OR: Executor executor = new EmbeddedExecutor(); // Build request with CLI arguments ExecutorRequest request = ExecutorRequest.builder() .cwd(baseDir) .arguments(Arrays.asList("package", "-DskipTests=true", "-X")) .build(); // Execute int exitCode = executor.execute(request); // Verify assertEquals(0, exitCode, "Build should succeed"); assertTrue(Files.exists(baseDir.resolve("target/my-app-1.0.jar")), "JAR file should exist"); } }
| maven-verifier Concept | maven-executor Equivalent |
|---|---|
new Verifier(baseDir) | ExecutorRequest.builder().cwd(baseDir).build() |
verifier.addCliArgument(arg) | Add to arguments list in ExecutorRequest |
verifier.setMavenDebug(true) | Add -X to arguments |
verifier.setAutoclean(false) | Manage manually or via arguments |
verifier.setForkJvm(true) | Use ForkedExecutor |
verifier.setForkJvm(false) | Use EmbeddedExecutor |
verifier.execute() | executor.execute(request) |
verifier.verifyErrorFreeLog() | Check exitCode == 0 |
verifier.verifyFilePresent(path) | Use Files.exists(Paths.get(...)) |
verifier.verifyTextInLog(text) | Capture and parse executor output |
Before:
verifier.setEnvironmentVariable("JAVA_HOME", "/path/to/java"); verifier.setEnvironmentVariable("MAVEN_OPTS", "-Xmx1024m");
After:
Map<String, String> env = new HashMap<>(); env.put("JAVA_HOME", "/path/to/java"); env.put("MAVEN_OPTS", "-Xmx1024m"); ExecutorRequest request = ExecutorRequest.builder() .cwd(baseDir) .arguments(args) .environmentVariables(env) .build();
maven-verifier included many helper methods like verifyFilePresent(), verifyTextInLog(), etc. These are not part of maven-executor's core responsibility. Instead:
Extract verification to separate utilities:
public class MavenTestUtils { public static void assertFileExists(Path base, String relativePath) { Path file = base.resolve(relativePath); assertTrue(Files.exists(file), "Expected file does not exist: " + file); } public static void assertLogContains(String log, String expectedText) { assertTrue(log.contains(expectedText), "Log does not contain expected text: " + expectedText); } public static void assertErrorFreeLog(String log) { assertFalse(log.contains("[ERROR]"), "Log contains errors"); } }
Before:
verifier.setLocalRepo("/custom/repo"); verifier.setUserSettingsFile("/path/to/settings.xml");
After:
ExecutorRequest request = ExecutorRequest.builder() .cwd(baseDir) .arguments(Arrays.asList( "package", "-Dmaven.repo.local=/custom/repo", "-s", "/path/to/settings.xml" )) .build();
Verifier class in your codebaseaddCliArgument() calls to arguments listFor large codebases, consider a gradual approach:
For gradual migration, you can create an adapter:
public class MavenExecutorAdapter { private final Path baseDir; private final List<String> arguments = new ArrayList<>(); private final Map<String, String> env = new HashMap<>(); private Executor executor = new ForkedExecutor(); public MavenExecutorAdapter(String baseDir) { this.baseDir = Paths.get(baseDir); } public void addCliArgument(String arg) { arguments.add(arg); } public void setEnvironmentVariable(String key, String value) { env.put(key, value); } public void setForkJvm(boolean fork) { executor = fork ? new ForkedExecutor() : new EmbeddedExecutor(); } public void execute() throws Exception { ExecutorRequest request = ExecutorRequest.builder() .cwd(baseDir) .arguments(arguments) .environmentVariables(env) .build(); int exitCode = executor.execute(request); if (exitCode != 0) { throw new Exception("Maven execution failed with exit code: " + exitCode); } } // Add other adapter methods as needed }
For migration questions or issues: