Подтвердить что ты не робот

Как получить доступ к иерархии зависимостей Maven в плагине

В моем плагине мне нужно обработать иерархию зависимостей и получить информацию (groupId, artifactId, version и т.д.) о каждой зависимости, и если она была исключена. Каков наилучший способ сделать это?

4b9b3361

Ответ 1

Плагин зависимостей имеет цель дерева, которая выполняет большую часть этой работы. Он обрабатывает MavenProject с помощью DependencyTreeBuilder, это возвращает DependencyNode с иерархической информацией об разрешенных зависимостях (и их транзитивных зависимостях).

Вы можете скопировать большую часть кода непосредственно из TreeMojo. Он использует CollectingDependencyNodeVisitor для пересечения дерева и создания List всех узлов.

Вы можете получить доступ к Artifact для node, вызвав getArtifact(), а затем получить информацию об артефакте по мере необходимости. Чтобы получить причину исключения, 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();
    }
}

Ответ 2

Вы можете использовать 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, версии и т.д.

Ответ 3

Попробуйте использовать Aether из jcabi-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
);

Ответ 5

Почему бы просто не вернуть все зависимости (как прямые, так и транзитивные) и проверить на исключение?

@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) ) { ... }
  }
}

Ответ 6

Вот обновленный пример 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;

Вернет только каталог классов, а не тот путь, который вы ожидаете.

Изменение requireDependencyCollection и requireDependencyResolution для разных значений позволит вам изменить масштаб того, что вы хотите захватить. maven documentation может предоставить более подробную информацию.

Ответ 7

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