How Maven's Legacy Repository Session Extension Works: Bridging Aether and Legacy APIs

Maven's LegacyRepositorySystemSessionExtender bridges the modern Eclipse Aether repository system with Maven's legacy ArtifactRepository API by copying mirror, proxy, and authentication selectors from the Aether session into legacy repository objects during session construction.

Apache Maven 4 uses the Eclipse Aether repository system internally, yet much of its core still depends on the older ArtifactRepository API. The legacy repository session extension mechanism ensures that modern Aether configuration—including mirrors, proxies, and credentials—flows seamlessly into these legacy objects that older plugins and core components expect.

Architecture and Integration Points

The extension sits at the intersection of Maven's modern Aether integration and its historical repository model. When Maven constructs a repository session, it must reconcile the modern selector-based configuration with the legacy object model that the rest of the codebase consumes.

The Aether-to-Legacy Bridge

Maven 4 maintains the ArtifactRepository interface for backward compatibility, but repository resolution now happens through Aether's RepositorySystem. The LegacyRepositorySystemSessionExtender (annotated with @Named and @Singleton in the apache/maven source) implements the RepositorySystemSessionExtender interface to transfer configuration data between these two worlds.

Session Construction Flow

The extension triggers during the session-building phase:

  1. Maven execution request – A MavenExecutionRequest contains the raw list of remote and plugin repositories defined in a POM or settings file.
  2. Aether selectorsMirrorSelector, ProxySelector, and AuthenticationSelector are created by the Aether RepositorySystem based on current settings.
  3. Extension invocation – The core session builder (such as DefaultMavenRepositorySystemSession) looks for a bean implementing RepositorySystemSessionExtender and invokes its extend method.
  4. Legacy population – After the extender runs, each ArtifactRepository in the request has its mirror, proxy, and authentication fields populated with values derived from the Aether selectors.

The Extension Process: Mirror, Proxy, and Authentication Injection

The extend method in LegacyRepositorySystemSessionExtender.java serves as the central entry point for transforming legacy repository objects. The method signature processes both remote and plugin repositories:

public void extend(
        MavenExecutionRequest request,
        Map<String, Object> config,
        MirrorSelector mirrorSelector,
        ProxySelector proxySelector,
        AuthenticationSelector authSelector) {
    // remote repositories
    injectMirror(request.getRemoteRepositories(), request.getMirrors());
    injectProxy(proxySelector, request.getRemoteRepositories());
    injectAuthentication(authSelector, request.getRemoteRepositories());

    // plugin repositories
    injectMirror(request.getPluginArtifactRepositories(), request.getMirrors());
    injectProxy(proxySelector, request.getPluginArtifactRepositories());
    injectAuthentication(authSelector, request.getPluginArtifactRepositories());
}

Mirror Injection via injectMirror

The injectMirror method iterates over each ArtifactRepository, finds the matching Aether Mirror using MavenRepositorySystem.getMirror, and replaces the repository's ID and URL with the mirror's data while preserving the original repository as a mirrored repository entry. This preserves a reference to the pre-mirrored repository for possible later use.

private void injectMirror(ArtifactRepository repo, Mirror mirror) {
    if (mirror != null) {
        ArtifactRepository original = MavenRepositorySystem.createArtifactRepository(
                repo.getId(), repo.getUrl(), repo.getLayout(),
                repo.getSnapshots(), repo.getReleases());

        repo.setMirroredRepositories(Collections.singletonList(original));
        repo.setId(mirror.getId());
        repo.setUrl(mirror.getUrl());
        repo.setBlocked(mirror.isBlocked());
    }
}

Proxy Resolution and Conversion

For proxy configuration, the extender uses ProxySelector to obtain an Aether Proxy object, then converts it into Maven's legacy org.apache.maven.repository.Proxy format. The getProxy method extracts host, protocol, and port, and handles authentication extraction via AuthenticationContext when credentials are present.

private org.apache.maven.repository.Proxy getProxy(ProxySelector selector,
                                                  ArtifactRepository repository) {
    RemoteRepository repo = RepositoryUtils.toRepo(repository);
    org.eclipse.aether.repository.Proxy proxy = selector.getProxy(repo);
    if (proxy != null) {
        org.apache.maven.repository.Proxy p = new org.apache.maven.repository.Proxy();
        p.setHost(proxy.getHost());
        p.setProtocol(proxy.getType());
        p.setPort(proxy.getPort());
        return p;
    }
    return null;
}

Authentication Extraction

Similarly, AuthenticationSelector provides an Aether Authentication object. The extender converts this into Maven's own Authentication object through the getAuthentication method, extracting the username, password, and optional private-key credentials.

private Authentication getAuthentication(AuthenticationSelector selector,
                                         ArtifactRepository repository) {
    RemoteRepository repo = RepositoryUtils.toRepo(repository);
    org.eclipse.aether.repository.Authentication auth = selector.getAuthentication(repo);
    if (auth != null) {
        AuthenticationContext ctx = AuthenticationContext.forRepository(null, repo);
        Authentication result = new Authentication(
                ctx.get(AuthenticationContext.USERNAME),
                ctx.get(AuthenticationContext.PASSWORD));
        result.setPrivateKey(ctx.get(AuthenticationContext.PRIVATE_KEY_PATH));
        result.setPassphrase(ctx.get(AuthenticationContext.PRIVATE_KEY_PASSPHRASE));
        ctx.close();
        return result;
    }
    return null;
}

Key Source Files and Implementation Details

The legacy extension mechanism resides in the following critical files within the apache/maven repository:

Why Maven Maintains This Compatibility Layer

Maven maintains the legacy repository session extension to ensure backward compatibility with plugins and extensions built against the legacy ArtifactRepository API. Rather than rewriting every consumer to understand Aether directly, Maven injects the modern configuration into the legacy objects once, letting existing code keep working while benefitting from the newer selector logic. This approach allows the core to migrate incrementally while preserving the ecosystem of existing plugins.

Summary

  • LegacyRepositorySystemSessionExtender acts as the bridge between Eclipse Aether and Maven's legacy ArtifactRepository API.
  • The extension copies mirror, proxy, and authentication configuration from Aether selectors into legacy repository objects during session construction.
  • The process happens transparently in DefaultMavenRepositorySystemSession before artifact resolution begins.
  • Key methods include extend for orchestration, injectMirror for URL replacement, and getAuthentication for credential transfer.
  • This mechanism preserves backward compatibility with thousands of existing Maven plugins while enabling modern Aether features.

Frequently Asked Questions

What is the purpose of LegacyRepositorySystemSessionExtender in Maven?

The LegacyRepositorySystemSessionExtender ensures that modern Eclipse Aether configuration (mirrors, proxies, and authentication) is available to Maven's legacy ArtifactRepository objects. It translates the modern selector-based repository system into the legacy object model that older Maven components and plugins expect, allowing Maven 4 to maintain backward compatibility while using Aether internally.

How does Maven map Aether mirrors to legacy ArtifactRepository objects?

The extender's injectMirror method uses MavenRepositorySystem.getMirror to find the matching Aether mirror for each repository. It then replaces the repository's ID and URL with the mirror's values while storing the original repository in the mirroredRepositories list. This allows the legacy system to resolve artifacts through the mirror while maintaining a reference to the original repository.

Where does the legacy repository session extension fit in Maven's startup sequence?

The extension occurs during session construction, specifically within DefaultMavenRepositorySystemSession or similar session builders. After the Aether RepositorySystem creates the MirrorSelector, ProxySelector, and AuthenticationSelector, the core invokes the RepositorySystemSessionExtender.extend() method to populate the MavenExecutionRequest's repository lists before artifact resolution begins.

Can plugins interact with the RepositorySystemSessionExtender directly?

No, plugins typically do not interact with the RepositorySystemSessionExtender directly. The interface is an internal SPI (Service Provider Interface) marked with @Named and @Singleton for dependency injection. Maven's core session builder automatically invokes the extender during initialization, ensuring that by the time plugin code executes, all ArtifactRepository objects already contain the correct mirror, proxy, and authentication configuration.

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 →