How do you setup and execute a MavenExecutionRequest with Maven Core v4.0.0?

291 Views Asked by At

I want to build a Maven project using the Maven Core (version 4.0.0-alpha-5) library. All I want right now is a working proof-of-concept to run the install phase. However, I have not been able to create a working example and I cannot find a single tutorial or demonstration on the internet.

My main method is quite straightforward, it shouldn't require explanation:

public static void main(String[] args) throws Exception {
    Injector injector = Guice.createInjector(new CompleteMavenModule());

    Maven maven = injector.getInstance(Maven.class);
    MavenExecutionRequestPopulator populator = injector.getInstance(MavenExecutionRequestPopulator.class);

    DefaultMavenExecutionRequest request = new DefaultMavenExecutionRequest();
    request.setPom(new File("C:\\Users\\lc70844\\eclipse-workspace\\TestProject\\pom.xml"));
    request.setGoals(Arrays.asList("install"));

    populator.populateDefaults(request);

    MavenExecutionResult result = maven.execute(request);
    if (result.hasExceptions())
        result.getExceptions().stream().forEach(Throwable::printStackTrace);
}

When I run this, I get the following exception:

org.codehaus.plexus.component.repository.exception.ComponentLookupException: java.util.NoSuchElementException
      role: org.eclipse.aether.repository.WorkspaceReader
  roleHint: reactor
    at org.codehaus.plexus.DefaultPlexusContainer.lookup(DefaultPlexusContainer.java:267)
    at org.codehaus.plexus.DefaultPlexusContainer.lookup(DefaultPlexusContainer.java:255)
    at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:246)
    at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:228)
    at org.apache.maven.DefaultMaven.execute(DefaultMaven.java:153)
    at com.nhbb.test.MavenTest.main(MavenTest.java:43)
Caused by: java.util.NoSuchElementException
    at org.eclipse.sisu.inject.LocatedBeans$Itr.next(LocatedBeans.java:141)
    at org.eclipse.sisu.inject.LocatedBeans$Itr.next(LocatedBeans.java:1)
    at org.eclipse.sisu.plexus.DefaultPlexusBeans$Itr.next(DefaultPlexusBeans.java:76)
    at org.eclipse.sisu.plexus.DefaultPlexusBeans$Itr.next(DefaultPlexusBeans.java:1)
    at org.codehaus.plexus.DefaultPlexusContainer.lookup(DefaultPlexusContainer.java:263)
    ... 5 more

Going back to my main method, you'll notice the Guice.createInjector(new CompleteMavenModule()). The CompleteMavenModule class is a Guice module I setup to provide me with a DefaultMaven instance:

import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import javax.inject.Named;
import javax.inject.Singleton;

import org.apache.maven.DefaultMaven;
import org.apache.maven.Maven;
import org.apache.maven.WorkspaceReaderModule;
import org.apache.maven.artifact.factory.ArtifactFactory;
import org.apache.maven.artifact.factory.DefaultArtifactFactory;
import org.apache.maven.artifact.handler.ArtifactHandler;
import org.apache.maven.artifact.handler.manager.ArtifactHandlerManager;
import org.apache.maven.artifact.handler.manager.DefaultArtifactHandlerManager;
import org.apache.maven.artifact.repository.layout.ArtifactRepositoryLayout;
import org.apache.maven.artifact.repository.layout.DefaultRepositoryLayout;
import org.apache.maven.artifact.repository.metadata.io.DefaultMetadataReader;
import org.apache.maven.artifact.repository.metadata.io.MetadataReader;
import org.apache.maven.classrealm.ClassRealmManager;
import org.apache.maven.classrealm.ClassRealmManagerDelegate;
import org.apache.maven.classrealm.DefaultClassRealmManager;
import org.apache.maven.eventspy.EventSpy;
import org.apache.maven.execution.BuildResumptionAnalyzer;
import org.apache.maven.execution.BuildResumptionDataRepository;
import org.apache.maven.execution.DefaultBuildResumptionAnalyzer;
import org.apache.maven.execution.DefaultBuildResumptionDataRepository;
import org.apache.maven.execution.DefaultMavenExecutionRequestPopulator;
import org.apache.maven.execution.MavenExecutionRequestPopulator;
import org.apache.maven.execution.MojoExecutionListener;
import org.apache.maven.execution.ProjectExecutionListener;
import org.apache.maven.execution.scope.internal.MojoExecutionScopeCoreModule;
import org.apache.maven.extension.internal.CoreExports;
import org.apache.maven.graph.DefaultGraphBuilder;
import org.apache.maven.graph.GraphBuilder;
import org.apache.maven.internal.impl.EventSpyImpl;
import org.apache.maven.lifecycle.LifecycleMappingDelegate;
import org.apache.maven.lifecycle.MojoExecutionConfigurator;
import org.apache.maven.lifecycle.internal.DefaultExecutionEventCatapult;
import org.apache.maven.lifecycle.internal.DefaultLifecycleExecutionPlanCalculator;
import org.apache.maven.lifecycle.internal.DefaultLifecycleMappingDelegate;
import org.apache.maven.lifecycle.internal.DefaultLifecycleTaskSegmentCalculator;
import org.apache.maven.lifecycle.internal.DefaultMojoExecutionConfigurator;
import org.apache.maven.lifecycle.internal.DefaultProjectArtifactFactory;
import org.apache.maven.lifecycle.internal.ExecutionEventCatapult;
import org.apache.maven.lifecycle.internal.LifecycleExecutionPlanCalculator;
import org.apache.maven.lifecycle.internal.LifecycleTaskSegmentCalculator;
import org.apache.maven.lifecycle.internal.ProjectArtifactFactory;
import org.apache.maven.lifecycle.internal.builder.Builder;
import org.apache.maven.lifecycle.internal.builder.multithreaded.MultiThreadedBuilder;
import org.apache.maven.model.building.DefaultModelProcessor;
import org.apache.maven.model.building.DefaultModelSourceTransformer;
import org.apache.maven.model.building.ModelProcessor;
import org.apache.maven.model.building.ModelSourceTransformer;
import org.apache.maven.model.io.DefaultModelReader;
import org.apache.maven.model.io.ModelReader;
import org.apache.maven.model.locator.DefaultModelLocator;
import org.apache.maven.model.locator.ModelLocator;
import org.apache.maven.model.superpom.DefaultSuperPomProvider;
import org.apache.maven.model.superpom.SuperPomProvider;
import org.apache.maven.plugin.BuildPluginManager;
import org.apache.maven.plugin.DefaultBuildPluginManager;
import org.apache.maven.plugin.DefaultExtensionRealmCache;
import org.apache.maven.plugin.DefaultMojosExecutionStrategy;
import org.apache.maven.plugin.DefaultPluginArtifactsCache;
import org.apache.maven.plugin.DefaultPluginDescriptorCache;
import org.apache.maven.plugin.DefaultPluginRealmCache;
import org.apache.maven.plugin.ExtensionRealmCache;
import org.apache.maven.plugin.LegacySupport;
import org.apache.maven.plugin.MavenPluginManager;
import org.apache.maven.plugin.MavenPluginPrerequisitesChecker;
import org.apache.maven.plugin.MojosExecutionStrategy;
import org.apache.maven.plugin.PluginArtifactsCache;
import org.apache.maven.plugin.PluginDescriptorCache;
import org.apache.maven.plugin.PluginRealmCache;
import org.apache.maven.plugin.internal.DefaultLegacySupport;
import org.apache.maven.plugin.internal.DefaultMavenPluginManager;
import org.apache.maven.plugin.internal.DefaultPluginDependenciesResolver;
import org.apache.maven.plugin.internal.MavenPluginInternalModule;
import org.apache.maven.plugin.internal.MavenPluginJavaPrerequisiteChecker;
import org.apache.maven.plugin.internal.MavenPluginMavenPrerequisiteChecker;
import org.apache.maven.plugin.internal.PluginDependenciesResolver;
import org.apache.maven.plugin.prefix.PluginPrefixResolver;
import org.apache.maven.plugin.prefix.internal.DefaultPluginPrefixResolver;
import org.apache.maven.plugin.version.PluginVersionResolver;
import org.apache.maven.plugin.version.internal.DefaultPluginVersionResolver;
import org.apache.maven.project.DefaultProjectBuilder;
import org.apache.maven.project.DefaultProjectBuildingHelper;
import org.apache.maven.project.DefaultProjectDependenciesResolver;
import org.apache.maven.project.DefaultProjectRealmCache;
import org.apache.maven.project.ProjectBuilder;
import org.apache.maven.project.ProjectBuildingHelper;
import org.apache.maven.project.ProjectDependenciesResolver;
import org.apache.maven.project.ProjectRealmCache;
import org.apache.maven.project.RepositorySessionDecorator;
import org.apache.maven.project.artifact.DefaultProjectArtifactsCache;
import org.apache.maven.project.artifact.ProjectArtifactsCache;
import org.apache.maven.project.collector.DefaultProjectsSelector;
import org.apache.maven.project.collector.ProjectsSelector;
import org.apache.maven.repository.RepositorySystem;
import org.apache.maven.repository.internal.MavenResolverModule;
import org.apache.maven.repository.legacy.LegacyRepositorySystem;
import org.apache.maven.rtinfo.RuntimeInformation;
import org.apache.maven.rtinfo.internal.DefaultRuntimeInformation;
import org.apache.maven.session.scope.internal.SessionScopeModule;
import org.apache.maven.settings.crypto.DefaultSettingsDecrypter;
import org.apache.maven.settings.crypto.SettingsDecrypter;
import org.codehaus.plexus.DefaultPlexusContainer;
import org.codehaus.plexus.PlexusContainer;
import org.eclipse.aether.connector.basic.BasicRepositoryConnectorFactory;
import org.eclipse.aether.repository.WorkspaceReader;
import org.eclipse.aether.spi.connector.RepositoryConnectorFactory;
import org.eclipse.aether.spi.connector.transport.TransporterFactory;
import org.eclipse.aether.transport.file.FileTransporterFactory;
import org.eclipse.aether.transport.http.ChecksumExtractor;
import org.eclipse.aether.transport.http.HttpTransporterFactory;
import org.sonatype.plexus.components.cipher.DefaultPlexusCipher;
import org.sonatype.plexus.components.sec.dispatcher.DefaultSecDispatcher;
import org.sonatype.plexus.components.sec.dispatcher.SecDispatcher;

import com.google.inject.AbstractModule;
import com.google.inject.Provides;
import com.google.inject.name.Names;
import com.google.inject.util.Providers;

@SuppressWarnings("deprecation")
public class CompleteMavenModule extends AbstractModule {

    @Override
    protected void configure() {
        // org.apache.maven.repository.internal.MavenResolverModule does not provide
        // bindings for all the necessary dependencies
        install(new MavenResolverModule());
        install(new SessionScopeModule());
        install(new MojoExecutionScopeCoreModule());
        install(new MavenPluginInternalModule());
        install(new WorkspaceReaderModule());

        // make module "complete" by binding things not bound by MavenResolverModule
        bind(Maven.class).to(DefaultMaven.class).in(Singleton.class);
        bind(EventSpy.class).annotatedWith(Names.named("impl")).to(EventSpyImpl.class);
        bind(Builder.class).annotatedWith(Names.named("multithreaded")).to(MultiThreadedBuilder.class);
        bind(MojosExecutionStrategy.class).to(DefaultMojosExecutionStrategy.class).in(Singleton.class);
        bind(ArtifactRepositoryLayout.class).to(DefaultRepositoryLayout.class).in(Singleton.class);
        bind(ArtifactHandlerManager.class).to(DefaultArtifactHandlerManager.class).in(Singleton.class);
        bind(BuildResumptionAnalyzer.class).to(DefaultBuildResumptionAnalyzer.class).in(Singleton.class);
        bind(BuildResumptionDataRepository.class).to(DefaultBuildResumptionDataRepository.class).in(Singleton.class);
        bind(GraphBuilder.class).annotatedWith(Names.named(GraphBuilder.HINT)).to(DefaultGraphBuilder.class)
                .in(Singleton.class);
        bind(ExecutionEventCatapult.class).to(DefaultExecutionEventCatapult.class).in(Singleton.class);
        bind(LifecycleExecutionPlanCalculator.class).to(DefaultLifecycleExecutionPlanCalculator.class)
                .in(Singleton.class);
        bind(LifecycleMappingDelegate.class).annotatedWith(Names.named("default"))
                .to(DefaultLifecycleMappingDelegate.class).in(Singleton.class);
        bind(MojoExecutionConfigurator.class).annotatedWith(Names.named("default"))
                .to(DefaultMojoExecutionConfigurator.class).in(Singleton.class);
        bind(LifecycleTaskSegmentCalculator.class).to(DefaultLifecycleTaskSegmentCalculator.class).in(Singleton.class);
        bind(ProjectArtifactFactory.class).to(DefaultProjectArtifactFactory.class).in(Singleton.class);
        bind(ArtifactFactory.class).to(DefaultArtifactFactory.class).in(Singleton.class);
        bind(ModelLocator.class).to(DefaultModelLocator.class).in(Singleton.class);
        bind(ModelReader.class).to(DefaultModelReader.class).in(Singleton.class);
        bind(ModelProcessor.class).to(DefaultModelProcessor.class).in(Singleton.class);
        bind(SuperPomProvider.class).to(DefaultSuperPomProvider.class).in(Singleton.class);
        bind(ModelSourceTransformer.class).to(DefaultModelSourceTransformer.class).in(Singleton.class);
        bind(BuildPluginManager.class).to(DefaultBuildPluginManager.class).in(Singleton.class);
        bind(LegacySupport.class).to(DefaultLegacySupport.class).in(Singleton.class);
        bind(MavenPluginManager.class).to(DefaultMavenPluginManager.class).in(Singleton.class);
        bind(MavenPluginPrerequisitesChecker.class).annotatedWith(Names.named("java"))
                .to(MavenPluginJavaPrerequisiteChecker.class);
        bind(MavenPluginPrerequisitesChecker.class).annotatedWith(Names.named("maven"))
                .to(MavenPluginMavenPrerequisiteChecker.class);
        bind(ClassRealmManager.class).to(DefaultClassRealmManager.class).in(Singleton.class);
        bind(ExtensionRealmCache.class).to(DefaultExtensionRealmCache.class).in(Singleton.class);
        bind(PluginArtifactsCache.class).to(DefaultPluginArtifactsCache.class).in(Singleton.class);
        bind(PluginDescriptorCache.class).to(DefaultPluginDescriptorCache.class).in(Singleton.class);
        bind(PluginRealmCache.class).to(DefaultPluginRealmCache.class).in(Singleton.class);
        bind(PluginDependenciesResolver.class).to(DefaultPluginDependenciesResolver.class).in(Singleton.class);
        bind(PluginPrefixResolver.class).to(DefaultPluginPrefixResolver.class).in(Singleton.class);
        bind(MetadataReader.class).to(DefaultMetadataReader.class).in(Singleton.class);
        bind(PluginVersionResolver.class).to(DefaultPluginVersionResolver.class).in(Singleton.class);
        bind(ProjectBuilder.class).to(DefaultProjectBuilder.class);
        bind(ProjectBuildingHelper.class).to(DefaultProjectBuildingHelper.class).in(Singleton.class);
        bind(ProjectDependenciesResolver.class).to(DefaultProjectDependenciesResolver.class);
        bind(ProjectRealmCache.class).to(DefaultProjectRealmCache.class).in(Singleton.class);
        bind(ProjectArtifactsCache.class).to(DefaultProjectArtifactsCache.class).in(Singleton.class);
        bind(ProjectsSelector.class).to(DefaultProjectsSelector.class).in(Singleton.class);
        bind(RepositorySystem.class).to(LegacyRepositorySystem.class).in(Singleton.class);
        bind(RuntimeInformation.class).to(DefaultRuntimeInformation.class).in(Singleton.class);
        bind(SettingsDecrypter.class).to(DefaultSettingsDecrypter.class).in(Singleton.class);
        bind(PlexusContainer.class).to(DefaultPlexusContainer.class).in(Singleton.class);
        bind(WorkspaceReader.class).annotatedWith(Names.named("ide")).toProvider(Providers.of(null))
                .in(Singleton.class);
        bind(SecDispatcher.class).annotatedWith(Names.named("maven"))
                .toInstance(new DefaultSecDispatcher(new DefaultPlexusCipher()));
        bind(MavenExecutionRequestPopulator.class).to(DefaultMavenExecutionRequestPopulator.class).in(Singleton.class);
        bind(CoreExports.class).toInstance(new CoreExports(null, Collections.emptySet(), Collections.emptySet()));

        bind(RepositoryConnectorFactory.class).annotatedWith(Names.named("basic"))
                .to(BasicRepositoryConnectorFactory.class);
        bind(TransporterFactory.class).annotatedWith(Names.named("file")).to(FileTransporterFactory.class);
        bind(TransporterFactory.class).annotatedWith(Names.named("http")).to(HttpTransporterFactory.class);
    }

    @Provides
    @Singleton
    List<RepositorySessionDecorator> getRepositorySessionDecorators() {
        // No implementations exist for
        // org.apache.maven.project.RepositorySessionDecorator
        return Collections.emptyList();
    }

    @Provides
    @Singleton
    List<ClassRealmManagerDelegate> getClassRealmManagerDelegates() {
        // No implementations exist for
        // org.apache.maven.classrealm.ClassRealmManagerDelegate
        return Collections.emptyList();
    }

    @Provides
    @Singleton
    List<MavenPluginPrerequisitesChecker> getMavenPluginPrerequisitesCheckers(
            @Named("java") MavenPluginPrerequisitesChecker java,
            @Named("maven") MavenPluginPrerequisitesChecker maven) {
        return Arrays.asList(java, maven);
    }

    @Provides
    @Singleton
    List<MojoExecutionListener> getMojoExecutionListeners(MojoExecutionListener listener) {
        return Arrays.asList(listener);
    }

    @Provides
    @Singleton
    Map<String, MojoExecutionConfigurator> provideMojoExecutionConfigurators(
            @Named("default") MojoExecutionConfigurator defaultConfigurator) {
        return Stream.of(defaultConfigurator).collect(Collectors.toMap(k -> "default", v -> v));
    }

    @Provides
    @Singleton
    Map<String, LifecycleMappingDelegate> provideLifecycleMappingDelegates(
            @Named("default") LifecycleMappingDelegate defaultDelegate) {
        return Stream.of(defaultDelegate).collect(Collectors.toMap(k -> "default", v -> v));
    }

    @Provides
    @Singleton
    Map<String, ArtifactHandler> provideArtifactHandlers() {
        // No implementations exist for CompleteResolverModule.provideArtifactHandlers()
        return Collections.emptyMap();
    }

    @Provides
    @Singleton
    Map<String, ArtifactRepositoryLayout> provideRepositoryLayouts(ArtifactRepositoryLayout defaultLayout) {
        return Stream.of(defaultLayout).collect(Collectors.toMap(k -> "default", v -> v));
    }

    @Provides
    @Singleton
    List<ProjectExecutionListener> provideProjectExecutionListeners() {
        // No listeners
        return Collections.emptyList();
    }

    @Provides
    @Singleton
    Map<String, Builder> provideLifecycleBuilders(@Named("multithreaded") Builder multi) {
        return Stream.of(multi).collect(Collectors.toMap(k -> "multithreaded", v -> v));
    }

    @Provides
    @Singleton
    List<EventSpy> provideEventSpies(@Named("impl") EventSpy impl) {
        return Arrays.asList(impl);
    }

    @Provides
    @Singleton
    Map<String, ChecksumExtractor> provideChecksumExtractors() {
        return Collections.emptyMap();
    }

    @Provides
    @Singleton
    Set<RepositoryConnectorFactory> provideRepositoryConnectorFactories(
            @Named("basic") RepositoryConnectorFactory basic) {
        Set<RepositoryConnectorFactory> factories = new HashSet<>();
        factories.add(basic);
        return Collections.unmodifiableSet(factories);
    }

    @Provides
    @Singleton
    Set<TransporterFactory> provideTransporterFactories(@Named("file") TransporterFactory file,
            @Named("http") TransporterFactory http) {
        Set<TransporterFactory> factories = new HashSet<>();
        factories.add(file);
        factories.add(http);
        return Collections.unmodifiableSet(factories);
    }

}

Right off the bat, I know that I am not doing this correctly. You'll notice these two lines:

install(new MavenPluginInternalModule());
install(new WorkspaceReaderModule());

I had to create these modules to setup bindings for ReadOnlyPluginParametersValidator, DefaultMavenPluginValidator, and ReactorReader, which are all package-private classes (the binding for ReactorReader was my attempt at addressing the error above). If these classes are private, it leads me to believe that some Maven class is supposed to setup these bindings for me. Judging by the fact that I have to create the bindings myself, I suspect that I am taking an improper approach to the dependency injection.

I noticed that Maven does not use Guice directly, but is working with the PlexusContainer interface in conjunction with Plexus Classworlds and Guice for dependency injection. I do not have a solid understanding of what these "Plexus" libraries are or how work, and I believe this is the root of my problem. Again, I cannot find documentation, examples, or demonstrations on how to use these libraries with Maven.

The exception I pasted above originated from this line in the DefaultMaven class:

try {
    WorkspaceReader reactorReader = container.lookup(WorkspaceReader.class, ReactorReader.HINT);
    repoSession.setWorkspaceReader(reactorReader);
} catch (ComponentLookupException e) {
    return addExceptionToResult(result, e);
}

In this snippet, container is a PlexusContainer instance, not a Guice injector. I am quite convinced at this point that I need to be setting up my dependency injection with this "Plexus" library rather than Guice, but how? There is nothing I can find explaining how to do this.


EDIT: Here is my pom.xml:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.example.test</groupId>
    <artifactId>core-maven-test</artifactId>
    <version>0.0.1</version>
    <properties>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
    <dependencies>
        <dependency>
            <groupId>com.google.inject</groupId>
            <artifactId>guice</artifactId>
            <version>5.1.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.maven</groupId>
            <artifactId>maven-core</artifactId>
            <version>4.0.0-alpha-5</version>
        </dependency>
        <dependency>
            <groupId>org.apache.maven</groupId>
            <artifactId>maven-compat</artifactId>
            <version>4.0.0-alpha-5</version>
        </dependency>
        <dependency>
            <groupId>org.apache.maven</groupId>
            <artifactId>maven-resolver-provider</artifactId>
            <version>4.0.0-alpha-5</version>
        </dependency>
        <dependency>
            <groupId>org.apache.maven.resolver</groupId>
            <artifactId>maven-resolver-connector-basic</artifactId>
            <version>1.9.7</version>
        </dependency>
        <dependency>
            <groupId>org.apache.maven.resolver</groupId>
            <artifactId>maven-resolver-transport-file</artifactId>
            <version>1.9.7</version>
        </dependency>
        <dependency>
            <groupId>org.apache.maven.resolver</groupId>
            <artifactId>maven-resolver-transport-http</artifactId>
            <version>1.9.7</version>
        </dependency>
        <dependency>
            <groupId>org.apache.maven.resolver</groupId>
            <artifactId>maven-resolver-spi</artifactId>
            <version>1.9.7</version>
        </dependency>
        <dependency>
            <groupId>org.apache.maven.resolver</groupId>
            <artifactId>maven-resolver-util</artifactId>
            <version>1.9.7</version>
        </dependency>
        <dependency>
            <groupId>org.apache.maven.resolver</groupId>
            <artifactId>maven-resolver-impl</artifactId>
            <version>1.9.7</version>
        </dependency>
    </dependencies>
</project>
0

There are 0 best solutions below