What Is the Role of MavenSession in a Maven Build Lifecycle?

MavenSession is the central execution context that represents a single invocation of Maven, holding the request configuration, reactor state, repository session, and build results while passing through every phase of the lifecycle to supply plugins with environmental data.

In the Apache Maven source code, MavenSession serves as the single source of truth for everything that happens during a build. Understanding the role of MavenSession in a Maven build lifecycle is essential for developing custom plugins or extending the core reactor. This class, defined in impl/maven-core/src/main/java/org/apache/maven/execution/MavenSession.java, acts as the bridge between the command-line invocation and the execution of individual Mojos.

Core Responsibilities of MavenSession

Holding the Execution Request

The session encapsulates the MavenExecutionRequest via the private field request, exposing command-line options, goals, and properties through methods like getRequest(), getGoals(), and getUserProperties(). This allows every component in the build to access the original intent of the invocation, including system properties and the list of modules to build.

Tracking Build Results

Through the result field, the session maintains the MavenExecutionResult, recording success states and any collected exceptions accessible via getResult(). This ensures that failures in one module can be captured and reported without immediately terminating the entire reactor.

Providing Repository System Access

The session supplies the RepositorySystemSession required by Aether for artifact resolution, available through getRepositorySession(). This connects the build to the local and remote repositories, enabling dependency downloads and metadata resolution.

Managing the Reactor State

MavenSession maintains the complete list of projects in the reactor via projects and allProjects, tracking the thread-local current project and exposing it through getCurrentProject() and getTopLevelProject(). It also provides the ProjectDependencyGraph via getProjectDependencyGraph() for topological ordering of multi-module builds.

Storing Plugin Contexts

The pluginContextsByProjectAndPluginKey map allows plugins to store state scoped to a specific project and plugin key, retrieved via getPluginContext(). This mechanism enables data persistence across different phases or repeated executions of the same plugin within a single session.

How MavenSession Drives the Build Lifecycle

During the build lifecycle, Maven creates the session immediately after parsing the command line and validating the MavenExecutionRequest. As the reactor executes each module, the session travels through every phase, providing context to each Mojo. The session is typically injected into Mojos using the ${session} expression, giving plugins access to the entire execution context.

Accessing Build Context from a Mojo

Plugins obtain contextual data by injecting the session and calling its accessor methods:

@Mojo(name = "show-info", defaultPhase = LifecyclePhase.VALIDATE, threadSafe = true)
public class ShowInfoMojo extends AbstractMojo {

    /** The current Maven session (injected by Maven). */
    @Parameter(defaultValue = "${session}", readonly = true)
    private MavenSession session;

    public void execute() throws MojoExecutionException {
        // Current project
        MavenProject project = session.getCurrentProject();

        // User-defined properties (-DmyProp=foo)
        String myProp = session.getUserProperties().getProperty("myProp");

        // Resolve the path of the local repository
        String localRepo = session.getLocalRepository().getBasedir().getAbsolutePath();

        getLog().info("Project: " + project.getArtifactId());
        getLog().info("myProp = " + myProp);
        getLog().info("Local repo = " + localRepo);
    }
}

Key implementation details: The methods getCurrentProject(), getUserProperties(), and getLocalRepository() are defined in MavenSession.java and provide the core integration points for plugin development.

Managing Plugin State Across Modules

The session enables stateful plugins to cache data across multiple module executions using the plugin context map:

// Inside a mojo that runs multiple times for different modules
public void execute() throws MojoExecutionException {
    MavenProject project = session.getCurrentProject();

    // Obtain (or create) a map scoped to this project & plugin
    Map<String, Object> ctx = session.getPluginContext(this.getDescriptor(), project);

    // Store a value the first time the plugin runs
    ctx.computeIfAbsent("startTime", k -> Instant.now());

    Instant start = (Instant) ctx.get("startTime");
    getLog().info("Plugin started at " + start);
}

The getPluginContext method guarantees a non-null map that survives for the duration of the session, allowing plugins to avoid recalculating expensive data for each module.

Custom Mojos can access the reactor’s topological ordering through the session:

ProjectDependencyGraph graph = session.getProjectDependencyGraph();
List<MavenProject> sorted = graph.getSortedProjects(); // topological order

This ProjectDependencyGraph, populated by Maven after the reactor is built, enables plugins to understand dependency relationships between modules and react to the overall build structure.

Thread Safety and Parallel Builds

The parallel flag indicates whether the reactor may execute modules concurrently, exposed via isParallel() and setParallel(boolean). For thread safety, Maven creates shallow clones of the session using the clone() method, ensuring each thread maintains its own "current project" via thread-local storage without corrupting the original session state. This design allows the session to act as a safe container for execution context even during highly parallel builds.

Summary

  • Central execution context: MavenSession represents a single Maven invocation from impl/maven-core/src/main/java/org/apache/maven/execution/MavenSession.java, holding all environmental data from start to finish.
  • Request and results: It encapsulates the MavenExecutionRequest and tracks the MavenExecutionResult through dedicated fields and accessor methods.
  • Repository and resolution: It provides the RepositorySystemSession required for dependency resolution via getRepositorySession().
  • Reactor management: Maintains project lists, current project state via thread-local storage, and the dependency graph for multi-module builds.
  • Plugin integration: Offers the getPluginContext() method for stateful plugin operations and accepts injection via the ${session} expression.
  • Concurrency support: Supports parallel builds through the parallel flag and safe cloning mechanisms that isolate per-thread state.

Frequently Asked Questions

What is the difference between MavenSession and MavenExecutionRequest?

MavenExecutionRequest, defined in api/maven-api/src/main/java/org/apache/maven/api/MavenExecutionRequest.java, captures the initial command-line configuration and user inputs before the build starts. MavenSession wraps that request and evolves throughout the lifecycle, accumulating results, repository sessions, and reactor state as the build progresses, making it the mutable container for execution context while the request remains the immutable snapshot of the original invocation.

How does MavenSession support parallel builds?

The session tracks whether the reactor should run modules concurrently via the parallel boolean flag. When parallel execution is enabled, Maven creates shallow clones of the MavenSession using the clone() method so each thread maintains its own current project via thread-local storage without interfering with other threads. This ensures that the getCurrentProject() method returns the correct project for each concurrent execution branch.

Can a plugin modify the MavenSession?

While plugins can read from the session and store data in plugin contexts via getPluginContext(), directly modifying core session attributes like the project list or execution request is not recommended and may lead to unpredictable build behavior. The session is intended to be the authoritative source of truth for the execution context, and modifications outside the intended extension points can break reactor consistency.

Where is MavenSession instantiated in the Maven source code?

The session is instantiated in the Maven core after the MavenExecutionRequest is built and validated, specifically within the execution logic in impl/maven-core/src/main/java/org/apache/maven/execution/MavenSession.java. It becomes the container for all subsequent build operations, including the reactor traversal and Mojo execution phases.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →