Understanding Maven's Execution: 6 Core Files Every Developer Should Know
The six key files that control Maven's execution are MavenCli.java, MavenExecutionRequest.java, Maven.java, DefaultMaven.java, MavenSession.java, and GraphBuilder.java, which handle everything from CLI parsing to reactor graph construction.
Apache Maven orchestrates Java builds through a sophisticated execution pipeline defined in the apache/maven repository. Understanding Maven's execution requires tracing how command-line arguments transform into a running build session through a specific chain of core classes. This guide examines the essential source files responsible for initializing, configuring, and executing your Maven projects.
Entry Point and Request Initialization
The execution journey begins with parsing user input and constructing a configuration object that travels through the entire build pipeline.
MavenCli.java: The Command-Line Interface
Located at compat/maven-embedder/src/main/java/org/apache/maven/cli/MavenCli.java, this class serves as the primary entry point for the mvn command. It parses CLI options, configures logging, loads core extensions, and ultimately constructs a MavenExecutionRequest before calling Maven.execute. Studying this file reveals how user input translates into structured execution parameters.
MavenExecutionRequest.java: The Configuration Container
The interface at impl/maven-core/src/main/java/org/apache/maven/execution/MavenExecutionRequest.java holds all configuration for a build, including goals, properties, repositories, profiles, and concurrency settings. Every option you specify on the command line—from -DskipTests to -T 4—ends up in this request object that downstream components consume throughout the build.
Execution Orchestration
Once the request is built, Maven delegates to a facade that coordinates the heavy lifting of session creation and lifecycle execution.
Maven.java: The Public API Facade
The interface at impl/maven-core/src/main/java/org/apache/maven/Maven.java provides a simple contract with a single execute(MavenExecutionRequest) method. This abstraction enables easy testing and extension while hiding the complexity of the underlying implementation.
DefaultMaven.java: Core Implementation
The concrete implementation at impl/maven-core/src/main/java/org/apache/maven/DefaultMaven.java performs the actual orchestration. This class creates the RepositorySystemSession, builds the MavenSession, fires lifecycle events, constructs the reactor graph via GraphBuilder, and finally invokes LifecycleStarter. This is where the execution pipeline truly comes together, bridging configuration and runtime.
Runtime State and Dependency Resolution
During execution, Maven maintains state and determines build order through specialized classes that manage project relationships.
MavenSession.java: Build State Container
Found at impl/maven-core/src/main/java/org/apache/maven/execution/MavenSession.java, this class holds the runtime state of a running build including the original request, execution result, top-level project, list of projects, dependency graph, and plugin contexts. Lifecycle listeners and participants receive this session object, making it crucial for understanding what data is available during plugin execution.
GraphBuilder.java: Reactor Construction
The class at impl/maven-core/src/main/java/org/apache/maven/graph/GraphBuilder.java constructs the ProjectDependencyGraph from the list of MavenProject instances, applying selectors like --projects and --also-make. This graph determines the order in which modules are built and serves as the foundation for parallel builds and reactor-based dependency resolution.
Programmatic Execution Example
You can run Maven's execution engine directly without invoking the CLI. This example demonstrates building a request and executing it programmatically:
import org.apache.maven.Maven;
import org.apache.maven.impl.DefaultMaven;
import org.apache.maven.execution.MavenExecutionRequest;
import org.apache.maven.execution.DefaultMavenExecutionRequest;
import org.apache.maven.execution.MavenExecutionResult;
// Build the request (equivalent to "mvn clean install -DskipTests")
MavenExecutionRequest request = new DefaultMavenExecutionRequest();
request.setGoals(List.of("clean", "install"));
request.getUserProperties().setProperty("skipTests", "true");
// Obtain a Maven implementation (normally injected via DI)
Maven maven = new DefaultMaven(
lookup, // org.apache.maven.api.services.Lookup
eventCatapult, // ExecutionEventCatapult
legacySupport, // LegacySupport
sessionScope,
repositorySessionFactory,
graphBuilder,
buildResumptionAnalyzer,
buildResumptionDataRepository,
superPomProvider,
defaultSessionFactory,
null /* ideWorkspaceReader */);
// Execute the build
MavenExecutionResult result = maven.execute(request);
// Check the outcome
if (result.hasExceptions()) {
result.getExceptions().forEach(Throwable::printStackTrace);
} else {
System.out.println("Build succeeded!");
}
After execution, inspect the session to examine reactor details:
MavenSession session = result.getSession();
System.out.println("Top directory: " + session.getTopDirectory());
System.out.println("Projects in reactor:");
session.getProjects().forEach(p -> System.out.println(" - " + p.getId()));
System.out.println("Dependency graph: " + session.getProjectDependencyGraph());
Summary
Understanding Maven's execution requires studying these six interconnected components:
MavenCli.javaparses command-line arguments and initializes the execution request atcompat/maven-embedder/src/main/java/org/apache/maven/cli/MavenCli.javaMavenExecutionRequest.javaencapsulates all build configuration atimpl/maven-core/src/main/java/org/apache/maven/execution/MavenExecutionRequest.javaMaven.javaprovides the public execution API atimpl/maven-core/src/main/java/org/apache/maven/Maven.javaDefaultMaven.javaimplements the core orchestration logic atimpl/maven-core/src/main/java/org/apache/maven/DefaultMaven.javaMavenSession.javamaintains runtime build state atimpl/maven-core/src/main/java/org/apache/maven/execution/MavenSession.javaGraphBuilder.javaconstructs the reactor dependency graph atimpl/maven-core/src/main/java/org/apache/maven/graph/GraphBuilder.java
Frequently Asked Questions
What is the difference between MavenExecutionRequest and MavenSession?
MavenExecutionRequest is the input configuration containing user-specified goals, properties, and profiles, while MavenSession is the runtime state container that includes the request, execution results, project list, and dependency graph. The request represents what you want to build; the session represents the actual running build state.
How does Maven determine the order of module builds?
Maven uses GraphBuilder.java to construct a ProjectDependencyGraph from the reactor projects, analyzing inter-module dependencies and applying CLI selectors like --projects. This graph determines the topological order for sequential builds and provides the basis for parallel execution threads.
Can I run Maven programmatically without using the CLI?
Yes, you can instantiate DefaultMaven.java directly and call execute() with a manually constructed DefaultMavenExecutionRequest. This approach is useful for embedding Maven in IDEs, CI systems, or custom build tools, bypassing the MavenCli.java entry point entirely.
Where does Maven handle command-line argument parsing?
Command-line parsing occurs in MavenCli.java within the compat/maven-embedder module. This class converts raw CLI arguments into a structured MavenExecutionRequest, handling options like -D properties, -P profiles, and -T threading before delegating to the core execution engine.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →