Как получить доступ к иерархии зависимостей Maven в плагине
В моем плагине мне нужно обработать иерархию зависимостей и получить информацию (groupId, artifactId, version и т. Д.) О каждой зависимости и, если она была исключена. Каков наилучший способ сделать это?
7 ответов
Плагин зависимостей имеет цель дерева, которая выполняет большую часть этой работы. Обрабатывает MavenProject
с использованием DependencyTreeBuilder
, это возвращает DependencyNode
с иерархической информацией о разрешенных зависимостях (и их транзитивных зависимостях).
Вы можете скопировать большую часть кода непосредственно из TreeMojo. Он использует CollectingDependencyNodeVisitor
пройти через дерево и произвести List
из всех узлов.
Вы можете получить доступ к Artifact
для узла, позвонив 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();
}
}
Вы можете использовать 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, version и т. Д.
Вот обновленный пример 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 документация может предоставить более подробную информацию.
Попробуй использовать 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
);
Почему бы просто не вернуть все зависимости (как прямые, так и транзитивные) и проверить на исключение?
@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) ) { ... }
}
}
Maven 3 использует эфир, здесь есть образец: https://docs.sonatype.org/display/AETHER/Home
Для 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();
}