MavenSession Object Structure and Usage: The Complete Apache Maven Guide
The MavenSession object is the central immutable state container for every Maven build, encapsulating the execution request, repository system session, project reactor, and thread-local context for multi-threaded builds.
The MavenSession class, located in org.apache.maven.execution within the apache/maven repository, serves as the definitive source of truth throughout the build lifecycle. It ties together user inputs, project models, and repository configurations into a single cohesive object that persists from command-line parsing to build completion. Understanding the MavenSession object structure and usage is essential for writing robust plugins, customizing build logic, and debugging complex multi-module projects.
Core State Components
The MavenSession implementation in impl/maven-core/src/main/java/org/apache/maven/execution/MavenSession.java maintains several critical fields that define the build environment:
- MavenExecutionRequest – Stores command-line goals, user properties, and repository settings supplied by the CLI
- MavenExecutionResult – Collects build outcomes, exceptions, and per-project results as execution proceeds
- RepositorySystemSession – The Aether (Eclipse Aether/Maven Resolver) session handling artifact resolution, mirrors, and proxies
- Project Reactor State –
List<MavenProject> projects,allProjects, andtopLevelProjectrepresenting the modules being built - ProjectDependencyGraph – The calculated dependency relationships between reactor projects
- Plugin Context Map –
pluginContextsByProjectAndPluginKeystoring per-project, per-plugin data that survives across multiple mojo executions - Thread-Local Current Project –
ThreadLocal<MavenProject> currentProjecttracking which module is currently being built on each thread
Session Construction and Initialization
Maven constructs the session through a specific sequence before the reactor builds begin:
- Parse Command Line – The CLI builds a
DefaultMavenExecutionRequestimplementing theMavenExecutionRequestinterface - Create Repository Session –
MavenSessionBuilderSupplierinimpl/maven-implconstructs the AetherRepositorySystemSession - Instantiate Session – The primary constructor stores the request, result, and repository session:
public MavenSession(RepositorySystemSession repositorySystemSession,
MavenExecutionRequest request,
MavenExecutionResult result)
- Populate Projects – After the reactor builds,
setProjects(List<MavenProject>)initializes the project list, sets thetopLevelProject, and configures the thread-local default - Configure Dependency Graph – Optional mutators set the
ProjectDependencyGraphand project map for multi-module navigation
Thread-Local Project Context
The session manages the current project concept through a ThreadLocal variable, enabling parallel builds while maintaining state isolation:
getCurrentProject()returns theMavenProjectcurrently being built on the calling threadsetCurrentProject(MavenProject project)updates the thread-local for aggregator plugins that switch contexts- This mechanism allows thread-safe access to project-specific data without passing project references through every method call
Repository System Integration
The repositorySystemSession field bridges Maven with the underlying Aether resolver:
RepositorySystemSession repoSession = session.getRepositorySession();
This session contains authentication details, mirror configurations, and caching policies. It remains immutable after construction, ensuring consistent artifact resolution throughout the build.
Plugin Context Storage
Plugins persist data across multiple executions using the session's plugin context mechanism:
Map<String, Object> context = session.getPluginContext(pluginDescriptor, project);
context.put("lastExecutionTime", System.currentTimeMillis());
The map is created lazily on first access and stored in pluginContextsByProjectAndPluginKey, surviving for the duration of the build to share state between related mojos.
Code Examples
Injecting MavenSession into a Mojo
Plugins access the session via parameter injection:
@Mojo(name = "report", defaultPhase = LifecyclePhase.VALIDATE)
public class ReportMojo extends AbstractMojo {
@Parameter(defaultValue = "${session}", readonly = true)
private MavenSession session;
public void execute() throws MojoExecutionException {
MavenProject current = session.getCurrentProject();
getLog().info("Building: " + current.getArtifactId());
getLog().info("Goals: " + session.getGoals());
}
}
Accessing Build Properties
Retrieve user-supplied properties and execution configuration:
Properties userProps = session.getUserProperties();
boolean isOffline = session.isOffline();
File localRepo = session.getLocalRepository().getBasedir();
Storing Cross-Mojo Data
Maintain state between plugin executions:
public void initializeBuild(MavenProject project, PluginDescriptor descriptor) {
Map<String, Object> ctx = session.getPluginContext(descriptor, project);
if (!ctx.containsKey("startTime")) {
ctx.put("startTime", Instant.now());
}
}
Creating Sessions Programmatically
For standalone tools or testing:
MavenExecutionRequest request = new DefaultMavenExecutionRequest()
.setGoals(Arrays.asList("clean", "install"))
.setBaseDirectory(new File("."));
MavenExecutionResult result = new MavenExecutionResult();
MavenSession session = new MavenSession(repoSystemSession, request, result);
session.setProjects(projectList);
Migration to the Maven 4 API
Maven 4 introduces org.apache.maven.api.Session as the modern abstraction. The legacy MavenSession maintains a reference to this new API via the session field, allowing plugins to bridge between legacy code and new API-centric extensions. Core components set this via setSession(Session apiSession) while maintaining backward compatibility with existing plugins that rely on the classic MavenSession API.
Summary
- MavenSession serves as the immutable container for all build state, located in
org.apache.maven.execution - Construction follows a strict path: request parsing → repository session creation → constructor invocation → project population
- Thread-local management enables safe parallel execution by tracking the current project per thread via
currentProject - Plugin contexts provide durable key-value storage across multiple executions of the same plugin on the same project
- Repository integration exposes the underlying Aether session through
getRepositorySession()for direct artifact manipulation - Maven 4 compatibility bridges legacy
MavenSessioncode with the neworg.apache.maven.api.Sessionabstraction
Frequently Asked Questions
How do I access the MavenSession inside a plugin?
Inject the session using the @Parameter annotation with defaultValue="${session}". This provides read-only access to the build state, including the current project, user properties, and repository configuration. Access the current project via session.getCurrentProject() to determine which module is being built.
What is stored in the MavenSession thread-local current project?
The currentProject ThreadLocal stores a reference to the MavenProject actively being built on the specific execution thread. During parallel builds, each thread maintains its own current project reference, allowing thread-safe access to project-specific data without synchronization overhead.
How does MavenSession differ from MavenProject?
MavenSession represents the global build state spanning all modules and the entire execution lifecycle, while MavenProject represents a single module's model (POM, dependencies, build configuration). The session contains the list of all projects and tracks which one is currently being built via the thread-local context.
Can I modify the MavenSession during a build?
Most MavenSession fields are immutable after construction, but the plugin context map and current project thread-local are mutable. Plugins can store data in getPluginContext() and change the current project via setCurrentProject(), but should not attempt to modify the execution request or repository session after initialization.
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 →