如何使用DependencyGraphBuilder以编程方式列出所有传递依赖项,包括Maven中被覆盖的依赖项?

7

这与其他问题类似(像这样的),但我想使用最新的API来完成。maven-dependency-plugin:tree verbose选项已经过时,并且在最新的(2.5.1)代码中无效,因此没有很好的示例来说明如何实现。


目前在此使用的新版Aether并未提供此类信息。只有旧版本的maven-dependency-plugin才提供此类信息(http://maven.40175.n5.nabble.com/maven-dependency-plugin-Questions-td5729997.html)。 - khmarbaise
我猜这意味着简短的答案是目前不可能。至少在Hervé将成为maven-core的解决方案之前。 - Ben
2个回答

5
我相信Aether实用类,来自于jcabi-aether,可以帮助您获取任何Maven artifact的所有依赖项列表,例如:
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
);

如果你不在Maven插件中:

File repo = new File("/tmp/local-repository");
MavenProject project = new MavenProject();
project.setRemoteProjectRepositories(
  Arrays.asList(
    new RemoteRepository(
      "maven-central",
      "default",
      "http://repo1.maven.org/maven2/"
    )
  )
);
Collection<Artifact> deps = new Aether(project, repo).resolve(
  new DefaultArtifact("junit", "junit-dep", "", "jar", "4.10"),
  "runtime"
);

您所需的唯一依赖项是:
<dependency>
  <groupId>com.jcabi</groupId>
  <artifactId>jcabi-aether</artifactId>
  <version>0.7.5</version>
</dependency>

好的...如果您想在MavenProject.getArtifact上使用它,那么这将如何工作?有什么办法可以做到这一点吗?(我已经在这里提出了这个问题:http://stackoverflow.com/questions/16480314/get-all-the-dependencies-of-a-mavenproject-including-transitive-ones-using-aet)。 - carlspring
尝试使用jcabi-aether中的实用类Classpath(我也回答了你的另一个问题)。 - yegor256
警告:jcabi-aether项目似乎已经被放弃了(他们的页面最后更新于8年前),而且其中任何内容都无法与现代版本的maven和/或aether一起使用。不要浪费时间在它上面。一个今天可用的答案是https://dev59.com/oZzha4cB1Zd3GeqPK9Xo#40820480。 - Mike Nakis

0

包括我的方法在内,因为如果在复合或多模块项目上工作,额外的步骤可能会成为您实际使用情况的一部分。

(Maven 3,我的运行时版本是3.6;没有直接依赖于Aether)

在我的情况下,我想从插件内部解析特定构件foo-runtime的依赖树;然而,

  • 某些依赖版本仅在其父级的foo-parent POM中可用(即在foo-runtime自己的POM中不存在)。
  • 父POM还具有其他详细信息,例如通过dependencyManagement排除一些foo-runtime的依赖项。

所以我必须:

  • 显式加载父模型,
  • 将子模型链接到它,
  • 填写子模型缺失的版本号(仍然不确定为什么Maven在链接父级后没有自动解析这些版本号),然后
  • 运行子依赖关系解析。
为了避免从头开始构建模型,我使用现有的 foo-api 资源派生出 foo-runtime 模型(在我的情况下,这些资源总是保证存在于正在构建的 Maven 项目中)。所有这些资源都共享相同的 groupId
    @Component
    public LifecycleDependencyResolver resolver;

    // ...

    // `artifacts` contains all artifacts of current/reactor `MavenProject` obtained via `project.getArtifacts()`
    private Set<Artifact> resolveRuntimeDeps(Set<Artifact> artifacts) throws MojoExecutionException {

        // foo-api will always be present; use it to derive coordinates for foo-runtime
        Artifact fooApi = artifacts.stream().filter(artifact -> "foo-api".equals(artifact.getArtifactId()))
                .findFirst().orElseThrow(() -> new MojoExecutionException("Unable to find foo-api"));

        Collection<String> scopes = Arrays.asList("compile", "runtime");

        MavenProject fooRoot = deriveProject(fooApi, "foo-parent");
        Model fooRootPom = fooRoot.getModel();

        MavenProject fooSrv = deriveProject(fooApi, "foo-runtime");
        fooSrv.setParent(fooRoot);

        // some foo-runtime deps depend on versions declared on parent pom; merge them
        Map<String, Artifact> depMgt = fooRootPom.getDependencyManagement().getDependencies().stream()
                .collect(Collectors.toMap(dep -> dep.getGroupId() + ":" + dep.getArtifactId() + ":" + dep.getType(), this::toArtifact));
        for (Dependency d : fooSrv.getDependencies()) {
            if (d.getVersion() == null) {
                Artifact managed = depMgt.get(d.getGroupId() + ":" + d.getArtifactId() + ":" + d.getType());
                if (managed != null) {
                    d.setVersion(managed.getVersion());
                }
            }
        }

        try {
            resolver.resolveProjectDependencies(fooSrv, scopes, scopes, session, false, Collections.emptySet());
            return fooSrv.getArtifacts();
        } catch (LifecycleExecutionException e) {
            throw new MojoExecutionException("Error resolving foo-runtime dependencies", e);
        }
    }

    // load POM for another artifact based on foo-api JAR available in current project
    private MavenProject deriveProject(Artifact fooApi, String artifactId) throws MojoExecutionException {
        Model pom;
        String pomPath = fooApi.getFile().getAbsolutePath().replaceAll("foo-api", artifactId).replaceAll("\\.jar$", ".pom");
        try (InputStream fooRootPomData = new FileInputStream(pomPath)) {
            pom = new MavenXpp3Reader().read(fooRootPomData);
            pom.setPomFile(new File(pomPath));
        } catch (IOException | XmlPullParserException e) {
            throw new MojoExecutionException("Error loading " + artifactId + " metadata", e);
        }

        // set these params to avoid skips/errors during resolution
        MavenProject proj = new MavenProject(pom);
        proj.setArtifact(toArtifact(pom));
        proj.setArtifactFilter(Objects::nonNull);
        proj.setRemoteArtifactRepositories(Collections.emptyList());
        return proj;
    }

    private Artifact toArtifact(Model model) {
        return new DefaultArtifact(
                Optional.ofNullable(model.getGroupId()).orElseGet(() -> model.getParent().getGroupId()), model.getArtifactId(),
                Optional.ofNullable(model.getVersion()).orElseGet(() -> model.getParent().getVersion()), "compile", model.getPackaging(), null,
                project.getArtifact().getArtifactHandler());
    }

    private Artifact toArtifact(Dependency dep) {
        return new DefaultArtifact(dep.getGroupId(), dep.getArtifactId(), dep.getVersion(), dep.getScope(), dep.getType(), dep.getClassifier(),
                project.getArtifact().getArtifactHandler());
    }

我尝试了几乎所有其他建议的方法,但它们都以某种错误结束。现在回头看,我怀疑许多这些错误可能是由于我的叶POM缺少一些工件的版本号造成的。似乎(可以接受),“模型丰富化”阶段-传播父版本等-由Maven流中的某个早期组件执行;当从头开始调用依赖关系解析器时,调用者必须至少部分地处理这个问题。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接