#StackBounty: #java #maven #aether Programatically getting an effective POM using Maven Resolver Provider

Bounty: 500

I need to programatically access the effective POM of a given POM file. Search on the interwebs have taken me to Maven Resolver Provider. This has replaced Eclipse Aether as a means of programmatic access to maven model resolution.

I have something that works:

public static void main(String[] args) throws Exception {
        DefaultServiceLocator locator = serviceLocator();
        RepositorySystem system = locator.getService(RepositorySystem.class);
        DefaultRepositorySystemSession session = MavenRepositorySystemUtils.newSession();
        LocalRepository localRepo = new LocalRepository("target/m2");
        session.setLocalRepositoryManager(system.newLocalRepositoryManager(session, localRepo));

        Constructor<ModelResolver> c = modelResolverCtor();
        RequestTrace requestTrace = new RequestTrace(null);
        ArtifactResolver artifactResolver = locator.getService(ArtifactResolver.class);
        VersionRangeResolver versionRangeResolver = locator.getService(VersionRangeResolver.class);
        RemoteRepositoryManager remoteRepositoryManager = locator.getService(RemoteRepositoryManager.class);
        List<RemoteRepository> repos = List.of(new RemoteRepository.Builder("central", "default", "https://repo.maven.apache.org/maven2/").build());
        ModelResolver modelResolver = c.newInstance(session, requestTrace, "context", artifactResolver, versionRangeResolver, remoteRepositoryManager, repos);

        DefaultModelBuildingRequest modelBuildingRequest = new DefaultModelBuildingRequest();
        String springBootPOMPath =
                "https://repo.maven.apache.org/maven2/org/springframework/boot/spring-boot/2.1.4.RELEASE/spring-boot-2.1.4.RELEASE.pom";
        File springBootPOM = downloadPOM(springBootPOMPath, HttpClientBuilder.create().build());
        modelBuildingRequest.setPomFile(springBootPOM);
        modelBuildingRequest.setModelResolver(modelResolver);
        DefaultModelBuilder modelBuilder = new DefaultModelBuilderFactory().newInstance();
        System.out.println(modelBuilder.build(modelBuildingRequest).getEffectiveModel().getDependencies());
    }

    private static DefaultServiceLocator serviceLocator() {
        DefaultServiceLocator locator = MavenRepositorySystemUtils.newServiceLocator();
        locator.addService(RepositoryConnectorFactory.class, BasicRepositoryConnectorFactory.class);
        locator.addService(TransporterFactory.class, FileTransporterFactory.class);
        locator.addService(TransporterFactory.class, HttpTransporterFactory.class);
        locator.addService(TransporterFactory.class, WagonTransporterFactory.class);
        return locator;
    }

    private static Constructor<ModelResolver> modelResolverCtor() throws ClassNotFoundException, NoSuchMethodException {
        @SuppressWarnings("unchecked") Class<ModelResolver> modelResolverClass =
                (Class<ModelResolver>) Class.forName("org.apache.maven.repository.internal.DefaultModelResolver");
        Constructor<ModelResolver> c = modelResolverClass.getDeclaredConstructor(RepositorySystemSession.class, RequestTrace.class,
                String.class, ArtifactResolver.class, VersionRangeResolver.class, RemoteRepositoryManager.class, List.class);
        c.setAccessible(true);
        return c;
    }

    private static File downloadPOM(String pomURL, HttpClient client) throws Exception {
        HttpGet request = new HttpGet(pomURL);
        HttpResponse response = client.execute(request);
        File outputFile = new File("target/" + Paths.get(new URI(pomURL).getPath()).getFileName().toString());
        try (InputStream contentStream = response.getEntity().getContent()) {
            Files.copy(contentStream, outputFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
        }
        return outputFile;
    }

which depends on the following:

<dependency>
    <groupId>org.apache.maven</groupId>
    <artifactId>maven-resolver-provider</artifactId>
    <version>3.6.0</version>
</dependency>
<dependency>
    <groupId>org.apache.maven.resolver</groupId>
    <artifactId>maven-resolver-connector-basic</artifactId>
    <version>1.3.3</version>
</dependency>
<dependency>
    <groupId>org.apache.maven.resolver</groupId>
    <artifactId>maven-resolver-transport-file</artifactId>
    <version>1.3.3</version>
</dependency>
<dependency>
    <groupId>org.apache.maven.resolver</groupId>
    <artifactId>maven-resolver-transport-http</artifactId>
    <version>1.3.3</version>
</dependency>
<dependency>
    <groupId>org.apache.maven.resolver</groupId>
    <artifactId>maven-resolver-transport-wagon</artifactId>
    <version>1.3.3</version>
</dependency>

This works fine but the ModelResolver is package-private and I have to reflect my way to get to it. My code can break on updates.

It seems I’m not using these libraries as intended. There isn’t much information by way of docs etc.


Get this bounty!!!

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.