Michele Sacchetti
Michele Sacchetti

Reputation: 163

Aether, how to get dependencies with hierarchy

I'm using eather to re-create the same structure of maven dependency:tree within my code. Following the documentation I found this useful example which correctly list the same depdendencys as the plugin but it lacks any "tree" information, it's just a flat list.

 public static void main( String[] args )
    throws Exception
{
    System.out.println( "------------------------------------------------------------" );
    System.out.println( ResolveTransitiveDependencies.class.getSimpleName() );

    RepositorySystem system = Booter.newRepositorySystem();

    RepositorySystemSession session = Booter.newRepositorySystemSession( system );

    Artifact artifact = new DefaultArtifact( "org.eclipse.aether:aether-impl:1.0.0.v20140518" );

    DependencyFilter classpathFlter = DependencyFilterUtils.classpathFilter( JavaScopes.COMPILE );

    CollectRequest collectRequest = new CollectRequest();
    collectRequest.setRoot( new Dependency( artifact, JavaScopes.COMPILE ) );
    collectRequest.setRepositories( Booter.newRepositories( system, session ) );

    DependencyRequest dependencyRequest = new DependencyRequest( collectRequest, classpathFlter );

    List<ArtifactResult> artifactResults =
        system.resolveDependencies( session, dependencyRequest ).getArtifactResults();

    for ( ArtifactResult artifactResult : artifactResults )
    {
        System.out.println( artifactResult.getArtifact() + " resolved to " + artifactResult.getArtifact().getFile() );
    }
}

I then wrote another piece of code to retrieve non-transitive dependencies and, invoking it recurively, was able to get a full dependency graph, but without any limitation, so I should implement some filtering/limit routine.

Since I'd like to keep as much as possible the same plugin logic, without introducing "my" filtering, is there any way to adapt the fist example in order to retrieve hierarchy information as well?

Upvotes: 3

Views: 1154

Answers (1)

Dzmitry Paulenka
Dzmitry Paulenka

Reputation: 1919

If you want exactly the same behavior, as plugin implements, I suggest to look into the plugin's source code here, so you will not miss any nuances. But the basic approach is to use collectRequest to collectDependencies, like this:

public static void main(String[] args) throws Exception {
    System.out.println("------------------------------------------------------------");

    RepositorySystem system = Booter.newRepositorySystem();

    RepositorySystemSession session = Booter.newRepositorySystemSession(system);

    Artifact artifact = new DefaultArtifact("org.apache.maven.plugins:maven-shade-plugin:2.3");

    DependencyFilter classpathFlter = DependencyFilterUtils.classpathFilter(JavaScopes.COMPILE);

    CollectRequest collectRequest = new CollectRequest();
    collectRequest.setRoot(new Dependency(artifact, JavaScopes.COMPILE));
    collectRequest.setRepositories(Booter.newRepositories(system, session));

    DependencyRequest dependencyRequest = new DependencyRequest(collectRequest, classpathFlter);

    List<ArtifactResult> artifactResults =
            system.resolveDependencies(session, dependencyRequest).getArtifactResults();

//        for (ArtifactResult artifactResult : artifactResults) {
//            System.out.println(artifactResult.getArtifact() + " resolved to " + artifactResult.getArtifact().getFile());
//        }

    //use collectDependencies to collect
    CollectResult collectResult = system.collectDependencies(session, collectRequest);
    DependencyNode node = collectResult.getRoot();
    node.accept(new TreeDependencyVisitor(new DependencyVisitor() {
        String indent = "";
        @Override
        public boolean visitEnter(DependencyNode dependencyNode) {
            System.out.println(indent + dependencyNode.getArtifact());
            indent += "    ";
            return true;
        }

        @Override
        public boolean visitLeave(DependencyNode dependencyNode) {
            indent = indent.substring(0, indent.length() - 4);
            return true;
        }
    }));

}

[EDIT:] To include test dependencies, you will need to customize session's depSelector, like this:

    DependencySelector depFilter =
            new AndDependencySelector(
                    new ScopeDependencySelector( "provided" ),
                    new OptionalDependencySelector(),
                    new ExclusionDependencySelector()
            );

And add classpathFilter to traversing:

DependencyFilter classpathFlter = DependencyFilterUtils.classpathFilter(JavaScopes.TEST);

node.accept(new TreeDependencyVisitor(new FilteringDependencyVisitor(new DependencyVisitor() {
    ...
}, classpathFlter)));

Still, this will not be exactly as dependency:tree, because it will actually list all the jars, that will go to test classpath. But with this you can actually further customize NodeVisitor to filter whatever you want.

Upvotes: 3

Related Questions