You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by sl...@apache.org on 2026/10/05 21:22:58 UTC
(maven-project-info-reports-plugin) 01/02: [MPIR-458] Replace maven-dependency-tree with Maven Resolver
This is an automated email from the ASF dual-hosted git repository.
slachiewicz pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven-project-info-reports-plugin.git
commit 73ded7ecbd63652ef3ce0779791a76df080420f5
Author: Sylwester Lachiewicz <sl...@apache.org>
AuthorDate: Wed Sep 30 18:29:32 2026 +0200
[MPIR-458] Replace maven-dependency-tree with Maven Resolver
The reports only need the artifact tree, so it is built from ProjectDependenciesResolver and RepositorySystem
directly; the verbose collection must keep omitted nodes, which convergence relies on.
---
pom.xml | 10 +-
.../report/projectinfo/DependenciesReport.java | 28 ++-
.../projectinfo/DependencyConvergenceReport.java | 72 ++-----
.../projectinfo/dependencies/Dependencies.java | 1 -
.../projectinfo/dependencies/DependencyNode.java | 110 ++++++++++
.../dependencies/DependencyNodeVisitor.java | 42 ++++
.../dependencies/DependencyTreeBuilder.java | 224 +++++++++++++++++++++
.../dependencies/DependencyTreeException.java | 32 +++
.../dependencies/DependencyVersionMap.java | 2 -
.../SinkSerializingDependencyNodeVisitor.java | 2 -
.../renderer/DependenciesRenderer.java | 2 +-
11 files changed, 440 insertions(+), 85 deletions(-)
diff --git a/pom.xml b/pom.xml
index bd834ff..d36e200 100644
--- a/pom.xml
+++ b/pom.xml
@@ -178,17 +178,17 @@ under the License.
<version>${mavenVersion}</version>
<scope>provided</scope>
</dependency>
- <dependency>
- <groupId>org.apache.maven.shared</groupId>
- <artifactId>maven-dependency-tree</artifactId>
- <version>3.3.0</version>
- </dependency>
<dependency>
<groupId>org.apache.maven.resolver</groupId>
<artifactId>maven-resolver-api</artifactId>
<version>${resolverVersion}</version>
<scope>provided</scope>
</dependency>
+ <dependency>
+ <groupId>org.apache.maven.resolver</groupId>
+ <artifactId>maven-resolver-util</artifactId>
+ <version>${resolverVersion}</version>
+ </dependency>
<dependency>
<groupId>org.apache.maven.plugin-tools</groupId>
diff --git a/src/main/java/org/apache/maven/report/projectinfo/DependenciesReport.java b/src/main/java/org/apache/maven/report/projectinfo/DependenciesReport.java
index 61c571c..13be4de 100644
--- a/src/main/java/org/apache/maven/report/projectinfo/DependenciesReport.java
+++ b/src/main/java/org/apache/maven/report/projectinfo/DependenciesReport.java
@@ -19,7 +19,6 @@
package org.apache.maven.report.projectinfo;
import javax.inject.Inject;
-import javax.inject.Named;
import java.io.BufferedReader;
import java.io.File;
@@ -38,17 +37,16 @@ import org.apache.maven.artifact.resolver.filter.ScopeArtifactFilter;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.plugins.annotations.ResolutionScope;
-import org.apache.maven.project.DefaultProjectBuildingRequest;
import org.apache.maven.project.ProjectBuilder;
-import org.apache.maven.project.ProjectBuildingRequest;
+import org.apache.maven.project.ProjectDependenciesResolver;
import org.apache.maven.report.projectinfo.dependencies.Dependencies;
import org.apache.maven.report.projectinfo.dependencies.DependenciesReportConfiguration;
+import org.apache.maven.report.projectinfo.dependencies.DependencyNode;
+import org.apache.maven.report.projectinfo.dependencies.DependencyTreeBuilder;
+import org.apache.maven.report.projectinfo.dependencies.DependencyTreeException;
import org.apache.maven.report.projectinfo.dependencies.RepositoryUtils;
import org.apache.maven.report.projectinfo.dependencies.renderer.DependenciesRenderer;
import org.apache.maven.reporting.MavenReportException;
-import org.apache.maven.shared.dependency.graph.DependencyGraphBuilder;
-import org.apache.maven.shared.dependency.graph.DependencyGraphBuilderException;
-import org.apache.maven.shared.dependency.graph.DependencyNode;
import org.apache.maven.shared.jar.classes.JarClassesAnalysis;
import org.codehaus.plexus.i18n.I18N;
import org.codehaus.plexus.util.IOUtil;
@@ -86,11 +84,11 @@ public class DependenciesReport extends AbstractProjectInfoReport {
// ----------------------------------------------------------------------
/**
- * Dependency graph builder component.
+ * Project dependencies resolver component.
*
- * @since 2.5
+ * @since 3.9.1
*/
- private final DependencyGraphBuilder dependencyGraphBuilder;
+ private final ProjectDependenciesResolver dependenciesResolver;
/**
* Jar classes analyzer component.
@@ -106,11 +104,11 @@ public class DependenciesReport extends AbstractProjectInfoReport {
RepositorySystem repositorySystem,
I18N i18n,
ProjectBuilder projectBuilder,
- @Named("default") DependencyGraphBuilder dependencyGraphBuilder,
+ ProjectDependenciesResolver dependenciesResolver,
JarClassesAnalysis classesAnalyzer,
RepositoryUtils repoUtils) {
super(repositorySystem, i18n, projectBuilder);
- this.dependencyGraphBuilder = dependencyGraphBuilder;
+ this.dependenciesResolver = dependenciesResolver;
this.classesAnalyzer = classesAnalyzer;
this.repoUtils = repoUtils;
}
@@ -191,11 +189,9 @@ public class DependenciesReport extends AbstractProjectInfoReport {
private DependencyNode resolveProject() {
try {
ArtifactFilter artifactFilter = new ScopeArtifactFilter(Artifact.SCOPE_TEST);
- ProjectBuildingRequest buildingRequest =
- new DefaultProjectBuildingRequest(getSession().getProjectBuildingRequest());
- buildingRequest.setProject(project);
- return dependencyGraphBuilder.buildDependencyGraph(buildingRequest, artifactFilter);
- } catch (DependencyGraphBuilderException e) {
+ return DependencyTreeBuilder.resolve(
+ dependenciesResolver, project, getSession().getRepositorySession(), artifactFilter);
+ } catch (DependencyTreeException e) {
getLog().error("Unable to build dependency tree.", e);
return null;
}
diff --git a/src/main/java/org/apache/maven/report/projectinfo/DependencyConvergenceReport.java b/src/main/java/org/apache/maven/report/projectinfo/DependencyConvergenceReport.java
index d81e498..5811553 100644
--- a/src/main/java/org/apache/maven/report/projectinfo/DependencyConvergenceReport.java
+++ b/src/main/java/org/apache/maven/report/projectinfo/DependencyConvergenceReport.java
@@ -44,21 +44,14 @@ import org.apache.maven.project.DefaultProjectBuildingRequest;
import org.apache.maven.project.MavenProject;
import org.apache.maven.project.ProjectBuilder;
import org.apache.maven.project.ProjectBuildingRequest;
+import org.apache.maven.report.projectinfo.dependencies.DependencyNode;
+import org.apache.maven.report.projectinfo.dependencies.DependencyNodeVisitor;
+import org.apache.maven.report.projectinfo.dependencies.DependencyTreeBuilder;
+import org.apache.maven.report.projectinfo.dependencies.DependencyTreeException;
import org.apache.maven.report.projectinfo.dependencies.DependencyVersionMap;
import org.apache.maven.report.projectinfo.dependencies.SinkSerializingDependencyNodeVisitor;
import org.apache.maven.reporting.MavenReportException;
import org.apache.maven.shared.artifact.filter.StrictPatternIncludesArtifactFilter;
-import org.apache.maven.shared.dependency.graph.DependencyCollectorBuilder;
-import org.apache.maven.shared.dependency.graph.DependencyCollectorBuilderException;
-import org.apache.maven.shared.dependency.graph.DependencyNode;
-import org.apache.maven.shared.dependency.graph.filter.AncestorOrSelfDependencyNodeFilter;
-import org.apache.maven.shared.dependency.graph.filter.AndDependencyNodeFilter;
-import org.apache.maven.shared.dependency.graph.filter.ArtifactDependencyNodeFilter;
-import org.apache.maven.shared.dependency.graph.filter.DependencyNodeFilter;
-import org.apache.maven.shared.dependency.graph.traversal.BuildingDependencyNodeVisitor;
-import org.apache.maven.shared.dependency.graph.traversal.CollectingDependencyNodeVisitor;
-import org.apache.maven.shared.dependency.graph.traversal.DependencyNodeVisitor;
-import org.apache.maven.shared.dependency.graph.traversal.FilteringDependencyNodeVisitor;
import org.codehaus.plexus.i18n.I18N;
import org.eclipse.aether.RepositorySystem;
@@ -92,19 +85,9 @@ public class DependencyConvergenceReport extends AbstractProjectInfoReport {
// Mojo parameters
// ----------------------------------------------------------------------
- /**
- * Raw dependency collector builder, will use it to build dependency tree.
- */
- private final DependencyCollectorBuilder dependencyCollectorBuilder;
-
@Inject
- protected DependencyConvergenceReport(
- RepositorySystem repositorySystem,
- I18N i18n,
- ProjectBuilder projectBuilder,
- DependencyCollectorBuilder dependencyCollectorBuilder) {
+ protected DependencyConvergenceReport(RepositorySystem repositorySystem, I18N i18n, ProjectBuilder projectBuilder) {
super(repositorySystem, i18n, projectBuilder);
- this.dependencyCollectorBuilder = dependencyCollectorBuilder;
}
// ----------------------------------------------------------------------
@@ -405,44 +388,16 @@ public class DependencyConvergenceReport extends AbstractProjectInfoReport {
* @return the serialized dependency tree
*/
private void serializeDependencyTree(DependencyNode rootNode, String key, Sink sink) {
- DependencyNodeVisitor visitor = getSerializingDependencyNodeVisitor(sink);
-
- visitor = new BuildingDependencyNodeVisitor(visitor);
+ List<String> patterns = Arrays.asList(key.split(","));
- DependencyNodeFilter nodeFilter = createDependencyNodeFilter(key);
+ getLog().debug("+ Filtering dependency tree by artifact include patterns: " + patterns);
- if (nodeFilter != null) {
- CollectingDependencyNodeVisitor collectingVisitor = new CollectingDependencyNodeVisitor();
- DependencyNodeVisitor firstPassVisitor = new FilteringDependencyNodeVisitor(collectingVisitor, nodeFilter);
- rootNode.accept(firstPassVisitor);
+ // keep only the nodes matching the key and their ancestors
+ DependencyNode tree = rootNode.prune(new StrictPatternIncludesArtifactFilter(patterns));
- DependencyNodeFilter secondPassFilter =
- new AncestorOrSelfDependencyNodeFilter(collectingVisitor.getNodes());
- visitor = new FilteringDependencyNodeVisitor(visitor, secondPassFilter);
+ if (tree != null) {
+ tree.accept(getSerializingDependencyNodeVisitor(sink));
}
-
- rootNode.accept(visitor);
- }
-
- /**
- * Gets the dependency node filter to use when serializing the dependency graph.
- *
- * @return the dependency node filter, or <code>null</code> if none required
- */
- private DependencyNodeFilter createDependencyNodeFilter(String includes) {
- List<DependencyNodeFilter> filters = new ArrayList<>();
-
- // filter includes
- if (includes != null) {
- List<String> patterns = Arrays.asList(includes.split(","));
-
- getLog().debug("+ Filtering dependency tree by artifact include patterns: " + patterns);
-
- ArtifactFilter artifactFilter = new StrictPatternIncludesArtifactFilter(patterns);
- filters.add(new ArtifactDependencyNodeFilter(artifactFilter));
- }
-
- return filters.isEmpty() ? null : new AndDependencyNodeFilter(filters);
}
/**
@@ -851,8 +806,9 @@ public class DependencyConvergenceReport extends AbstractProjectInfoReport {
*/
private DependencyNode getNode(ProjectBuildingRequest buildingRequest) throws MavenReportException {
try {
- return dependencyCollectorBuilder.collectDependencyGraph(buildingRequest, filter);
- } catch (DependencyCollectorBuilderException e) {
+ return DependencyTreeBuilder.collectVerbose(
+ repositorySystem, buildingRequest.getProject(), buildingRequest.getRepositorySession(), filter);
+ } catch (DependencyTreeException e) {
throw new MavenReportException("Could not build dependency tree: " + e.getMessage(), e);
}
}
diff --git a/src/main/java/org/apache/maven/report/projectinfo/dependencies/Dependencies.java b/src/main/java/org/apache/maven/report/projectinfo/dependencies/Dependencies.java
index 150afc1..29a913a 100644
--- a/src/main/java/org/apache/maven/report/projectinfo/dependencies/Dependencies.java
+++ b/src/main/java/org/apache/maven/report/projectinfo/dependencies/Dependencies.java
@@ -28,7 +28,6 @@ import java.util.jar.JarEntry;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.project.MavenProject;
-import org.apache.maven.shared.dependency.graph.DependencyNode;
import org.apache.maven.shared.jar.JarAnalyzer;
import org.apache.maven.shared.jar.JarData;
import org.apache.maven.shared.jar.classes.JarClasses;
diff --git a/src/main/java/org/apache/maven/report/projectinfo/dependencies/DependencyNode.java b/src/main/java/org/apache/maven/report/projectinfo/dependencies/DependencyNode.java
new file mode 100644
index 0000000..0cfd7a8
--- /dev/null
+++ b/src/main/java/org/apache/maven/report/projectinfo/dependencies/DependencyNode.java
@@ -0,0 +1,110 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.report.projectinfo.dependencies;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
+
+/**
+ * A node of the dependency tree shown by the reports: an artifact and the nodes it brings in.
+ *
+ * @since 3.9.1
+ */
+public class DependencyNode {
+ private final DependencyNode parent;
+
+ private final Artifact artifact;
+
+ private final boolean optional;
+
+ private List<DependencyNode> children = Collections.emptyList();
+
+ DependencyNode(DependencyNode parent, Artifact artifact, boolean optional) {
+ this.parent = parent;
+ this.artifact = artifact;
+ this.optional = optional;
+ }
+
+ public Artifact getArtifact() {
+ return artifact;
+ }
+
+ public DependencyNode getParent() {
+ return parent;
+ }
+
+ public List<DependencyNode> getChildren() {
+ return children;
+ }
+
+ void setChildren(List<DependencyNode> children) {
+ this.children = Collections.unmodifiableList(children);
+ }
+
+ public String toNodeString() {
+ return artifact + (optional ? " (optional)" : "");
+ }
+
+ /**
+ * Visits this node and its descendants depth-first.
+ *
+ * @param visitor the visitor
+ * @return the result of {@link DependencyNodeVisitor#endVisit(DependencyNode)} for this node
+ */
+ public boolean accept(DependencyNodeVisitor visitor) {
+ if (visitor.visit(this)) {
+ for (DependencyNode child : children) {
+ if (!child.accept(visitor)) {
+ break;
+ }
+ }
+ }
+ return visitor.endVisit(this);
+ }
+
+ /**
+ * Copies this tree keeping only the nodes that match the filter and their ancestors.
+ *
+ * @param filter the filter
+ * @return the pruned copy, or <code>null</code> if no node matches
+ */
+ public DependencyNode prune(ArtifactFilter filter) {
+ return prune(null, filter);
+ }
+
+ private DependencyNode prune(DependencyNode newParent, ArtifactFilter filter) {
+ DependencyNode copy = new DependencyNode(newParent, artifact, optional);
+ List<DependencyNode> copiedChildren = new ArrayList<>();
+ for (DependencyNode child : children) {
+ DependencyNode copiedChild = child.prune(copy, filter);
+ if (copiedChild != null) {
+ copiedChildren.add(copiedChild);
+ }
+ }
+ if (copiedChildren.isEmpty() && !filter.include(artifact)) {
+ return null;
+ }
+ copy.setChildren(copiedChildren);
+ return copy;
+ }
+}
diff --git a/src/main/java/org/apache/maven/report/projectinfo/dependencies/DependencyNodeVisitor.java b/src/main/java/org/apache/maven/report/projectinfo/dependencies/DependencyNodeVisitor.java
new file mode 100644
index 0000000..257f225
--- /dev/null
+++ b/src/main/java/org/apache/maven/report/projectinfo/dependencies/DependencyNodeVisitor.java
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.report.projectinfo.dependencies;
+
+/**
+ * Visitor of a {@link DependencyNode} tree.
+ *
+ * @since 3.9.1
+ */
+public interface DependencyNodeVisitor {
+ /**
+ * Starts visiting a node.
+ *
+ * @param node the node
+ * @return <code>true</code> to visit the children of the node
+ */
+ boolean visit(DependencyNode node);
+
+ /**
+ * Ends visiting a node.
+ *
+ * @param node the node
+ * @return <code>true</code> to visit the following siblings of the node
+ */
+ boolean endVisit(DependencyNode node);
+}
diff --git a/src/main/java/org/apache/maven/report/projectinfo/dependencies/DependencyTreeBuilder.java b/src/main/java/org/apache/maven/report/projectinfo/dependencies/DependencyTreeBuilder.java
new file mode 100644
index 0000000..8fdd3e3
--- /dev/null
+++ b/src/main/java/org/apache/maven/report/projectinfo/dependencies/DependencyTreeBuilder.java
@@ -0,0 +1,224 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.report.projectinfo.dependencies;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.maven.RepositoryUtils;
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
+import org.apache.maven.model.Dependency;
+import org.apache.maven.project.DefaultDependencyResolutionRequest;
+import org.apache.maven.project.DependencyResolutionException;
+import org.apache.maven.project.DependencyResolutionRequest;
+import org.apache.maven.project.DependencyResolutionResult;
+import org.apache.maven.project.MavenProject;
+import org.apache.maven.project.ProjectDependenciesResolver;
+import org.eclipse.aether.DefaultRepositorySystemSession;
+import org.eclipse.aether.RepositorySystem;
+import org.eclipse.aether.RepositorySystemSession;
+import org.eclipse.aether.artifact.ArtifactTypeRegistry;
+import org.eclipse.aether.collection.CollectRequest;
+import org.eclipse.aether.collection.DependencyCollectionException;
+import org.eclipse.aether.collection.DependencySelector;
+import org.eclipse.aether.graph.DependencyFilter;
+import org.eclipse.aether.util.artifact.JavaScopes;
+import org.eclipse.aether.util.graph.selector.AndDependencySelector;
+import org.eclipse.aether.util.graph.selector.ExclusionDependencySelector;
+import org.eclipse.aether.util.graph.selector.OptionalDependencySelector;
+import org.eclipse.aether.util.graph.transformer.ConflictResolver;
+import org.eclipse.aether.util.graph.transformer.JavaScopeDeriver;
+import org.eclipse.aether.util.graph.transformer.JavaScopeSelector;
+import org.eclipse.aether.util.graph.transformer.NearestVersionSelector;
+import org.eclipse.aether.util.graph.transformer.SimpleOptionalitySelector;
+
+/**
+ * Builds the {@link DependencyNode} trees of a project directly from Maven Resolver.
+ *
+ * @since 3.9.1
+ */
+public final class DependencyTreeBuilder {
+ private DependencyTreeBuilder() {}
+
+ /**
+ * Builds the tree Maven resolves for the project, without downloading any artifact but the POMs.
+ *
+ * @param resolver the project dependencies resolver
+ * @param project the project
+ * @param session the repository session
+ * @param filter filters the artifacts of the nodes below the root, may be <code>null</code>
+ * @return the root node
+ * @throws DependencyTreeException if the dependencies cannot be resolved
+ */
+ public static DependencyNode resolve(
+ ProjectDependenciesResolver resolver,
+ MavenProject project,
+ RepositorySystemSession session,
+ ArtifactFilter filter)
+ throws DependencyTreeException {
+ DependencyResolutionRequest request = new DefaultDependencyResolutionRequest();
+ request.setMavenProject(project);
+ request.setRepositorySession(session);
+ // only download the poms, not the artifacts
+ DependencyFilter noArtifacts = (node, parents) -> false;
+ request.setResolutionFilter(noArtifacts);
+
+ DependencyResolutionResult result;
+ try {
+ result = resolver.resolve(request);
+ } catch (DependencyResolutionException e) {
+ throw new DependencyTreeException(
+ "Could not resolve following dependencies: " + e.getResult().getUnresolvedDependencies(), e);
+ }
+
+ return toNode(null, result.getDependencyGraph(), project.getArtifact(), filter);
+ }
+
+ /**
+ * Collects the tree of the project including the nodes omitted for a conflict or a duplicate, which
+ * {@link #resolve} leaves out.
+ *
+ * @param repositorySystem the repository system
+ * @param project the project
+ * @param session the repository session
+ * @param filter filters the artifacts of the nodes below the root, may be <code>null</code>
+ * @return the root node
+ * @throws DependencyTreeException if the dependencies cannot be collected
+ */
+ public static DependencyNode collectVerbose(
+ RepositorySystem repositorySystem,
+ MavenProject project,
+ RepositorySystemSession session,
+ ArtifactFilter filter)
+ throws DependencyTreeException {
+ DefaultRepositorySystemSession verboseSession = new DefaultRepositorySystemSession(session);
+ verboseSession.setConfigProperty(ConflictResolver.CONFIG_PROP_VERBOSE, true);
+ verboseSession.setDependencyGraphTransformer(new ConflictResolver(
+ new NearestVersionSelector(),
+ new JavaScopeSelector(),
+ new SimpleOptionalitySelector(),
+ new JavaScopeDeriver()));
+ verboseSession.setDependencySelector(new AndDependencySelector(
+ new DirectScopeDependencySelector(JavaScopes.TEST),
+ new DirectScopeDependencySelector(JavaScopes.PROVIDED),
+ new OptionalDependencySelector(),
+ new ExclusionDependencySelector()));
+
+ Artifact projectArtifact = project.getArtifact();
+
+ CollectRequest collectRequest = new CollectRequest();
+ collectRequest.setRootArtifact(RepositoryUtils.toArtifact(projectArtifact));
+ collectRequest.setRepositories(RepositoryUtils.toRepos(project.getRemoteArtifactRepositories()));
+
+ ArtifactTypeRegistry stereotypes = verboseSession.getArtifactTypeRegistry();
+ for (Dependency dependency : project.getDependencies()) {
+ collectRequest.addDependency(RepositoryUtils.toDependency(dependency, stereotypes));
+ }
+ if (project.getDependencyManagement() != null) {
+ for (Dependency dependency : project.getDependencyManagement().getDependencies()) {
+ collectRequest.addManagedDependency(RepositoryUtils.toDependency(dependency, stereotypes));
+ }
+ }
+
+ try {
+ return toNode(
+ null,
+ repositorySystem
+ .collectDependencies(verboseSession, collectRequest)
+ .getRoot(),
+ projectArtifact,
+ filter);
+ } catch (DependencyCollectionException e) {
+ throw new DependencyTreeException("Could not collect dependencies: " + e.getResult(), e);
+ }
+ }
+
+ private static DependencyNode toNode(
+ DependencyNode parent,
+ org.eclipse.aether.graph.DependencyNode node,
+ Artifact artifact,
+ ArtifactFilter filter) {
+ DependencyNode current = new DependencyNode(parent, artifact, artifact.isOptional());
+
+ List<DependencyNode> children = new ArrayList<>(node.getChildren().size());
+ for (org.eclipse.aether.graph.DependencyNode child : node.getChildren()) {
+ Artifact childArtifact = toArtifact(child.getDependency());
+ if (filter == null || filter.include(childArtifact)) {
+ children.add(toNode(current, child, childArtifact, filter));
+ }
+ }
+ current.setChildren(children);
+
+ return current;
+ }
+
+ private static Artifact toArtifact(org.eclipse.aether.graph.Dependency dependency) {
+ Artifact artifact = RepositoryUtils.toArtifact(dependency.getArtifact());
+ artifact.setScope(dependency.getScope());
+ artifact.setOptional(dependency.isOptional());
+ return artifact;
+ }
+
+ /**
+ * Excludes a scope from the direct dependencies' own dependencies (depth 2 and deeper) only.
+ */
+ private static final class DirectScopeDependencySelector implements DependencySelector {
+ private final String scope;
+
+ private final int depth;
+
+ DirectScopeDependencySelector(String scope) {
+ this(scope, 0);
+ }
+
+ private DirectScopeDependencySelector(String scope, int depth) {
+ this.scope = scope;
+ this.depth = depth;
+ }
+
+ @Override
+ public boolean selectDependency(org.eclipse.aether.graph.Dependency dependency) {
+ return depth < 2 || !scope.equals(dependency.getScope());
+ }
+
+ @Override
+ public DependencySelector deriveChildSelector(
+ org.eclipse.aether.collection.DependencyCollectionContext context) {
+ return depth >= 2 ? this : new DirectScopeDependencySelector(scope, depth + 1);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null || getClass() != obj.getClass()) {
+ return false;
+ }
+ DirectScopeDependencySelector other = (DirectScopeDependencySelector) obj;
+ return depth == other.depth && scope.equals(other.scope);
+ }
+
+ @Override
+ public int hashCode() {
+ return 31 * (31 + depth) + scope.hashCode();
+ }
+ }
+}
diff --git a/src/main/java/org/apache/maven/report/projectinfo/dependencies/DependencyTreeException.java b/src/main/java/org/apache/maven/report/projectinfo/dependencies/DependencyTreeException.java
new file mode 100644
index 0000000..97c4210
--- /dev/null
+++ b/src/main/java/org/apache/maven/report/projectinfo/dependencies/DependencyTreeException.java
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.report.projectinfo.dependencies;
+
+/**
+ * Signals that the dependency tree of a project could not be built.
+ *
+ * @since 3.9.1
+ */
+public class DependencyTreeException extends Exception {
+ private static final long serialVersionUID = 1L;
+
+ public DependencyTreeException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/src/main/java/org/apache/maven/report/projectinfo/dependencies/DependencyVersionMap.java b/src/main/java/org/apache/maven/report/projectinfo/dependencies/DependencyVersionMap.java
index 3cfe705..f463332 100644
--- a/src/main/java/org/apache/maven/report/projectinfo/dependencies/DependencyVersionMap.java
+++ b/src/main/java/org/apache/maven/report/projectinfo/dependencies/DependencyVersionMap.java
@@ -24,8 +24,6 @@ import java.util.List;
import java.util.Map;
import org.apache.maven.artifact.Artifact;
-import org.apache.maven.shared.dependency.graph.DependencyNode;
-import org.apache.maven.shared.dependency.graph.traversal.DependencyNodeVisitor;
/**
* @author Simon Wang
diff --git a/src/main/java/org/apache/maven/report/projectinfo/dependencies/SinkSerializingDependencyNodeVisitor.java b/src/main/java/org/apache/maven/report/projectinfo/dependencies/SinkSerializingDependencyNodeVisitor.java
index 6d6c879..3b9532e 100644
--- a/src/main/java/org/apache/maven/report/projectinfo/dependencies/SinkSerializingDependencyNodeVisitor.java
+++ b/src/main/java/org/apache/maven/report/projectinfo/dependencies/SinkSerializingDependencyNodeVisitor.java
@@ -21,8 +21,6 @@ package org.apache.maven.report.projectinfo.dependencies;
import java.util.List;
import org.apache.maven.doxia.sink.Sink;
-import org.apache.maven.shared.dependency.graph.DependencyNode;
-import org.apache.maven.shared.dependency.graph.traversal.DependencyNodeVisitor;
/**
* A dependency node visitor that serializes visited nodes to a sink writer. It's used to serialize tree in project
diff --git a/src/main/java/org/apache/maven/report/projectinfo/dependencies/renderer/DependenciesRenderer.java b/src/main/java/org/apache/maven/report/projectinfo/dependencies/renderer/DependenciesRenderer.java
index ce48a98..ec50f4d 100644
--- a/src/main/java/org/apache/maven/report/projectinfo/dependencies/renderer/DependenciesRenderer.java
+++ b/src/main/java/org/apache/maven/report/projectinfo/dependencies/renderer/DependenciesRenderer.java
@@ -55,9 +55,9 @@ import org.apache.maven.report.projectinfo.LicenseMapping;
import org.apache.maven.report.projectinfo.ProjectInfoReportUtils;
import org.apache.maven.report.projectinfo.dependencies.Dependencies;
import org.apache.maven.report.projectinfo.dependencies.DependenciesReportConfiguration;
+import org.apache.maven.report.projectinfo.dependencies.DependencyNode;
import org.apache.maven.report.projectinfo.dependencies.RepositoryUtils;
import org.apache.maven.report.projectinfo.dependencies.renderer.DependenciesRenderer.TotalCell.SummaryTableRowOrder;
-import org.apache.maven.shared.dependency.graph.DependencyNode;
import org.apache.maven.shared.jar.JarData;
import org.apache.maven.shared.jar.classes.JarClasses;
import org.apache.maven.shared.jar.classes.JarVersionedRuntime;