Aether,如何获得与层次结构的依赖关系

Aether, how to get dependencies with hierarchy

我正在使用 eather 在我的代码中重新创建与 maven dependency:tree 相同的结构。 根据文档,我发现这个有用的 example 它正确地列出了与插件相同的依赖关系,但它缺少任何 "tree" 信息,它只是一个简单的列表。

 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() );
    }
}

然后我编写了另一段代码来检索非传递依赖项,并递归调用它,能够获得完整的依赖关系图,但没有任何限制,所以我应该实现一些 filtering/limit 例程。

由于我想尽可能保持相同的插件逻辑,而不引入 "my" 过滤,是否有任何方法可以修改第一个示例以检索层次结构信息?

如果你想要 exactly the same 行为,作为插件实现,我建议查看插件的源代码 here,这样你就不会错过任何细微差别。但是基本的做法是使用collectRequestcollectDependencies,像这样:

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;
        }
    }));

}

[编辑:] 要包含测试依赖项,您需要自定义会话的 depSelector,如下所示:

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

并在遍历中加入classpathFilter:

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

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

不过,这不会与 dependency:tree 完全相同,因为它实际上会列出所有的 jar,它们将用于测试类路径。但是有了这个你实际上可以进一步自定义 NodeVisitor 来过滤你想要的任何东西。