【问题标题】:How to get access to Maven's dependency hierarchy within a plugin如何在插件中访问 Maven 的依赖层次结构
【发布时间】:2010-12-25 18:32:29
【问题描述】:

在我的插件中,我需要处理依赖层次结构并获取有关每个依赖项以及是否被排除的信息(groupId、artifactId、版本等)。最好的方法是什么?

【问题讨论】:

    标签: maven maven-plugin maven-dependency-plugin aether


    【解决方案1】:

    对于 Maven 3,您可以使用 DependencyGraphBuilder。它的作用与 DependencyTreeBuilder 几乎相同。

    这是一个例子

        import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
        import org.apache.maven.artifact.resolver.filter.IncludesArtifactFilter;
        import org.apache.maven.execution.MavenSession;
        import org.apache.maven.model.Dependency;
        import org.apache.maven.plugins.annotations.ResolutionScope;
        import org.apache.maven.plugins.annotations.LifecyclePhase;
        import org.apache.maven.shared.dependency.graph.DependencyGraphBuilder;
    
        import org.apache.maven.shared.dependency.graph.DependencyNode;
        import org.apache.maven.shared.dependency.graph.traversal.CollectingDependencyNodeVisitor;
    
        public class AnanlyzeTransitiveDependencyMojo extends AbstractMojo{
    
            @Parameter(defaultValue = "${project}", readonly = true, required = true)
            private MavenProject project;
    
            @Parameter(defaultValue = "${session}", readonly = true, required = true)
            private MavenSession session;
    
            @Component(hint="maven3")
            private DependencyGraphBuilder dependencyGraphBuilder;
    
            @Override
            public void execute() throws MojoExecutionException, MojoFailureException {
        // If you want to filter out certain dependencies.
                 ArtifactFilter artifactFilter = new IncludesArtifactFilter("groupId:artifactId:version");
                 ProjectBuildingRequest buildingRequest = new DefaultProjectBuildingRequest(session.getProjectBuildingRequest());
                 buildingRequest.setProject(project);
                try{
                   DependencyNode depenGraphRootNode = dependencyGraphBuilder.buildDependencyGraph(buildingRequest, artifactFilter);
                   CollectingDependencyNodeVisitor visitor = new  CollectingDependencyNodeVisitor();
                   depenGraphRootNode.accept(visitor);
                   List<DependencyNode> children = visitor.getNodes();
    
                   getLog().info("CHILDREN ARE :");
                   for(DependencyNode node : children) {
                       Artifact atf = node.getArtifact();
                }
    }catch(Exception e) {
        e.printStackTrace();
    }
    

    【讨论】:

    • pom 是什么样子的。无论我做什么,在运行我的插件时我都会得到NoClassDefFoundErrors for org/sonatype/aether
    【解决方案2】:

    这是一个最新的 Maven3 示例,说明如何获取所有依赖项(包括传递性)以及如何访问文件本身(例如,如果您需要将路径添加到类路径)。

    // Default phase is not necessarily important.
    // Both requiresDependencyCollection and requiresDependencyResolution are extremely important however!
    @Mojo(name = "simple", defaultPhase = LifecyclePhase.PROCESS_RESOURCES, requiresDependencyCollection = ResolutionScope.COMPILE_PLUS_RUNTIME, requiresDependencyResolution = ResolutionScope.COMPILE_PLUS_RUNTIME)
    public class SimpleMojo extends AbstractMojo {
      @Parameter(defaultValue = "${project}", readonly = true)
      private MavenProject mavenProject;
    
      @Override
      public void execute() throws MojoExecutionException, MojoFailureException {
        for (final Artifact artifact : mavenProject.getArtifacts()) {
          // Do whatever you need here.
          // If having the actual file (artifact.getFile()) is not important, you do not need requiresDependencyResolution.
        }
      }
    }
    

    更改 Mojo 中的参数是我错过的一个非常重要的部分。没有它,如下所示的行:

    @Parameter(defaultValue = "${project.compileClasspathElements}", readonly = true, required = true)
    private List<String> compilePath;
    

    只会返回类目录,而不是您期望的路径。

    将 requiresDependencyCollection 和 requiresDependencyResolution 更改为不同的值将允许您更改要抓取的范围。 maven documentation 可以提供更多细节。

    【讨论】:

    • 这是最好的答案(最新且全面)。我创建了一个帐户并回答了一些问题,这样我就可以获得足够的业力来对此进行投票。谢谢。
    • 尽管我投票支持该答案,但似乎使用此方法无法解决二级传递依赖关系。
    • 嗨,我怎样才能让它在我的自定义扩展中工作?有人可以看看这个问题吗?非常感谢您的帮助stackoverflow.com/questions/51888672/…
    • 如果你想让这个更棒一点,请包含项目依赖项。我收到 java.lang.NoClassDefFoundError: org/eclipse/aether/RepositorySystemSession ,我无法弄清楚出了什么问题。如果我添加 eclipse aether 依赖项,我会得到 org.apache.maven.artifact.versioning.DefaultArtifactVersion.compareTo(Lorg/apache/maven/artifact/versioning/ArtifactVersion;)I java.lang.NoSuchMethodError
    【解决方案3】:

    尝试使用jcabi-aether 中的Aether 实用程序类来获取任何工件的所有依赖项的列表:

    File repo = this.session.getLocalRepository().getBasedir();
    Collection<Artifact> deps = new Aether(this.getProject(), repo).resolve(
      new DefaultArtifact("junit", "junit-dep", "", "jar", "4.10"),
      JavaScopes.RUNTIME
    );
    

    【讨论】:

    【解决方案4】:

    您可以使用MavenProject#getDependencyArtifacts()MavenProject#getDependencies()(后者也返回传递依赖)。

    /**
     * Test Mojo
     *
     * @goal test
     * @requiresDependencyResolution compile
     */
    public class TestMojo extends AbstractMojo {
    
        /**
         * The Maven Project.
         *
         * @parameter expression="${project}"
         * @required
         * @readonly
         */
        private MavenProject project = null;
    
        /**
         * Execute Mojo.
         *
         * @throws MojoExecutionException If an error occurs.
         * @throws MojoFailureException If an error occurs.
         */
        public void execute() throws MojoExecutionException,
    MojoFailureException {
    
            ...
    
            Set dependencies = project.getDependencies();
    
           ...
        }
    
    }
    

    我不完全确定,但我认为这两种方法都会返回一组 Artifact 实现,这些实现公开了 groupId、artifactId、版本等的 getter。

    【讨论】:

    • +1 如果您需要获取所有 已解决 依赖项,这是一个比我更简单的解决方案,但如果您想了解有关排除的依赖项的信息,您需要的不仅仅是这个
    • 该死,你是对的,我错过了关于排除依赖项的要点。所以这并不能回答 OP 问题。
    • 是的,我毕竟是依赖项,所以我可以报告为什么不包括在内,不过感谢您提供的信息
    • 在 Maven 3.x 中 getDependencies() 不返回传递的 deps
    • 在 Maven 3.x 中,有一个 [setResolvedArtifacts][1] 方法,但是它的字段是私有的... [1] maven.apache.org/ref/3.0.3/maven-core/apidocs/org/apache/maven/…
    【解决方案5】:

    依赖插件具有完成大部分工作的tree goal。它使用DependencyTreeBuilder 处理MavenProject,这将返回一个DependencyNode,其中包含有关已解析依赖项(及其传递依赖项)的分层信息。

    您可以直接从 TreeMojo 复制大部分代码。它使用CollectingDependencyNodeVisitor 遍历树并生成所有节点的List

    您可以通过调用getArtifact() 访问该节点的Artifact,然后根据需要获取工件信息。要获取排除原因,DependencyNode 有一个 getState() 方法,该方法返回一个 int 指示是否已包含依赖项,或者如果不包含,则省略它的原因是什么(DependencyNode 类中有常量可以检查返回值反对)

    //All components need this annotation, omitted for brevity
    
    /**
     * @component
     * @required
     * @readonly
     */
    private ArtifactFactory artifactFactory;
    private ArtifactMetadataSource artifactMetadataSource;
    private ArtifactCollector artifactCollector;
    private DependencyTreeBuilder treeBuilder;
    private ArtifactRepository localRepository;
    private MavenProject project;
    
    public void execute() throws MojoExecutionException, MojoFailureException {
        try {
            ArtifactFilter artifactFilter = new ScopeArtifactFilter(null);
    
            DependencyNode rootNode = treeBuilder.buildDependencyTree(project,
                    localRepository, artifactFactory, artifactMetadataSource,
                    artifactFilter, artifactCollector);
    
            CollectingDependencyNodeVisitor visitor = 
                new CollectingDependencyNodeVisitor();
    
            rootNode.accept(visitor);
    
            List<DependencyNode> nodes = visitor.getNodes();
            for (DependencyNode dependencyNode : nodes) {
                int state = dependencyNode.getState();
                Artifact artifact = dependencyNode.getArtifact();
                if(state == DependencyNode.INCLUDED) {                    
                    //...
                } 
            }
        } catch (DependencyTreeBuilderException e) {
            // TODO handle exception
            e.printStackTrace();
        }
    }
    

    【讨论】:

    • +1 非常好,谢谢!但是,sn-p 包含一个小错误: List nodes = visitor.getNodes();在 for 循环之上。
    • 其中大部分在 Maven3 中已被弃用。有人愿意用 Maven3(未弃用)解决方案进行更新吗?
    • 哪些依赖项描述了所有这些类?
    【解决方案6】:

    为什么不直接取回所有依赖项(包括直接依赖项和传递依赖项)并检查排除项?

    @Parameter(property = "project", required = true, readonly = true)
    private MavenProject project;
    
    public void execute() throws MojoExecutionException
    {
      for (Artifact a : project.getArtifacts()) {
        if( a.getScope().equals(Artifact.SCOPE_TEST) ) { ... }
        if( a.getScope().equals(Artifact.SCOPE_PROVIDED) ) { ... }
        if( a.getScope().equals(Artifact.SCOPE_RUNTIME) ) { ... }
      }
    }
    

    【讨论】:

      【解决方案7】:

      Maven 3 使用以太,这里有示例: https://docs.sonatype.org/display/AETHER/Home

      【讨论】:

      猜你喜欢
      • 2015-12-03
      • 2019-02-03
      • 1970-01-01
      • 2012-08-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多