42

In my plugin I need to process the dependency hierarchy and get information (groupId, artifactId, version etc) about each dependency and if it was excluded. What is the best way to do this?

Sled
  • 18,541
  • 27
  • 119
  • 168
talk to frank
  • 1,821
  • 4
  • 20
  • 21
  • If you happen to need to do this for an *arbitrary artifact* while honoring parent POMs, exclusions etc, [check this approach](https://stackoverflow.com/questions/13200497/how-to-programmatically-list-all-transitive-dependencies-including-overridden-o#70823705) – Janaka Bandara Jan 23 '22 at 16:20

7 Answers7

30

The dependency plugin has the tree goal that does most of this work. It processes a MavenProject using the DependencyTreeBuilder, this returns a DependencyNode with hierarchical information about the resolved dependencies (and their transitive dependencies).

You can copy much of the code directly from the TreeMojo. It uses the CollectingDependencyNodeVisitor to traverse the tree and produce a List of all the nodes.

You can access the Artifact for the node by calling getArtifact(), then get the artifact information as needed. To get the exclusion reason, DependencyNode has a getState() method that returns an int indicating if the dependency has been included, or if not what the reason for omitting it was (there are constants in the DependencyNode class to check the return value against)

//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();
    }
}
mkobit
  • 43,979
  • 12
  • 156
  • 150
Rich Seller
  • 83,208
  • 23
  • 172
  • 177
22

You could use MavenProject#getDependencyArtifacts() or MavenProject#getDependencies() (the later one returns also transitive dependencies).

/**
 * 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();

       ...
    }

}

I'm not totally sure but I think both methods return a collection of Artifact implementations that expose getters for groupId, artifactId, version, etc.

mkobit
  • 43,979
  • 12
  • 156
  • 150
Pascal Thivent
  • 562,542
  • 136
  • 1,062
  • 1,124
  • 3
    +1 This is a simpler solution than mine if you need to get all *resolved* dependencies, but if you want to find out information about excluded dependencies you need more than this – Rich Seller Sep 29 '09 at 12:02
  • Damn, you are right, I missed the point about excluded dependencies. So this doesn't answer the OP question. – Pascal Thivent Sep 29 '09 at 12:13
  • yes I'm after all dependencies so I can report why they weren't included, thanks for the information though – talk to frank Sep 29 '09 at 14:43
  • 18
    in Maven 3.x `getDependencies()` doesn't return transitive deps – yegor256 Sep 15 '11 at 10:04
  • 1
    in Maven 3.x, there is a [setResolvedArtifacts][1] method, but its field private... [1] http://maven.apache.org/ref/3.0.3/maven-core/apidocs/org/apache/maven/project/MavenProject.html#setResolvedArtifacts%28java.util.Set%29 – Renaud Jan 31 '12 at 16:41
  • The @Parameter must be outside comments and capitalised. Teach me to cut'n'paste. – TimP Nov 11 '13 at 16:30
  • how to get transitive dependencies in maven 3? getDependencies doesnt reolve trans dependencies. – gabber12 Feb 11 '15 at 06:47
  • This is the easiest and simplest way to resolve and get dependencies from within a mojo. This is the better answer. – Nambi Feb 26 '15 at 02:22
  • You probably meant `getArtifacts` method which will retrieve all dependency artefacts including transitive ones. The `getDependencyArtifacts` method is deprecated. – scrutari Dec 27 '16 at 17:17
18

Here is an up to date, Maven3 example on how to get all dependencies (including transitive) as well as have access to the files themselves (if you for instance need to add the paths to a classpath).

// 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.
    }
  }
}

Changing the parameters in the Mojo is a very important piece that I was missing. Without it, lines like the following:

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

Will only return the classes directory, not the path you expect.

Changing the requiresDependencyCollection and requiresDependencyResolution to different values will allow you to change the scope of what you want to grab. The maven documentation can provide more detail.

Lukas Eder
  • 211,314
  • 129
  • 689
  • 1,509
wrestang
  • 553
  • 7
  • 17
  • 1
    This is the best answer (up to date & comprehensive). I created an account & answered some questions just so I can get enough karma to have the right to upvote this. Thanks. – Hugues M. Apr 29 '17 at 15:22
  • Despite i voted for that answer it seems that second level transitive dependencies are not resolved using this method. – Abbadon Jun 08 '18 at 16:16
  • Hi, how can I get this to work in my custom extension? Can someone please look at this question? greatly appreciate your help https://stackoverflow.com/questions/51888672/maven3-how-to-get-all-the-project-dependencies-in-a-custom-maven-extension – h-kach Aug 19 '18 at 16:21
  • If you want to make this slightly more awesome, please include the project dependencies. I am getting java.lang.NoClassDefFoundError: org/eclipse/aether/RepositorySystemSession and i can't quite figure out what is wrong. If i add the eclipse aether dependencies, i instead end up with org.apache.maven.artifact.versioning.DefaultArtifactVersion.compareTo(Lorg/apache/maven/artifact/versioning/ArtifactVersion;)I java.lang.NoSuchMethodError – Martin Nielsen Jun 06 '19 at 16:24
  • How do you resolve these dependencies' file paths? – Cardinal System Mar 29 '23 at 13:46
6

Try to use Aether utility class from jcabi-aether to get a list of all dependencies of any 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
);
mkobit
  • 43,979
  • 12
  • 156
  • 150
yegor256
  • 102,010
  • 123
  • 446
  • 597
  • Hi, can I do this in this scenario as well ? Appreciate your help https://stackoverflow.com/questions/51888672/maven3-how-to-get-all-the-project-dependencies-in-a-custom-maven-extension – h-kach Aug 19 '18 at 16:22
4

Why not just get back all the dependencies (both direct and transitive ones) and check for exclusion?

@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) ) { ... }
  }
}
kane
  • 5,465
  • 6
  • 44
  • 72
2

Maven 3 use aether, there is sample here : https://docs.sonatype.org/display/AETHER/Home

Yann Le Moigne
  • 612
  • 6
  • 16
  • 3
    Sorry, down voting for not including content in stackoverflow in case of broken links - link is now broken. – Greg Domjan Jun 16 '15 at 16:52
  • Aether [was disowned by Eclipse](https://projects.eclipse.org/projects/technology.aether/reviews/termination-review), but subsequently [adopted by Apache](https://maven.apache.org/resolver/)! – earcam Oct 06 '18 at 14:46
  • ... it's a trivial update from Eclipse Aether 1.1.0 to Apache Aether 1.1.1; just GIDs for the most part. [org.apache.maven.resolver](https://search.maven.org/search?q=g:org.apache.maven.resolver) and [maven-resolver-provider](https://search.maven.org/search?q=g:org.apache.maven%20AND%20a:maven-resolver-provider&core=gav) – earcam Oct 06 '18 at 14:56
1

For Maven 3 you can use DependencyGraphBuilder. It does pretty much the same thing as DependencyTreeBuilder.

Here is the example

    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();
}
Lukas Eder
  • 211,314
  • 129
  • 689
  • 1,509
poojaN
  • 61
  • 2
  • What does the pom look like. Whatever I do, I get `NoClassDefFoundError`s for `org/sonatype/aether` when running my plugin – mibutec Jun 07 '20 at 08:37
  • Try: org.apache.maven.shared maven-dependency-tree 3.2.1 org.eclipse.aether * – lolcio Apr 13 '23 at 16:23