如何在插件中访问Maven的依赖性层次结构
-
18-09-2019 - |
题
在我的插件中,我需要处理依赖关系层次结构并获取有关每个依赖关系以及是否被排除的信息(GroupID,ArtifactID,版本等)。做这个的最好方式是什么?
解决方案
依赖关系插件具有 树目标 大部分工作都可以。它处理一个 MavenProject
使用 DependencyTreeBuilder
, ,这返回 DependencyNode
借助有关解决的依赖性(及其及其依赖性)的分层信息。
您可以直接从Treemojo直接复制大部分代码。它使用 CollectingDependencyNodeVisitor
穿越树并产生一个 List
在所有节点中。
您可以访问 Artifact
通过调用节点 getArtifact()
, ,然后根据需要获取工件信息。要获得排除原因, DependencyNode
有个 getState()
返回int的方法表示依赖关系是否已包括在内,或者如果不是省略的原因(依赖项诺德类中有常数以检查返回值相反)
//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#getDependendencyArtifacts() 或者 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();
...
}
}
我不确定,但我认为这两种方法都返回 人工制品 暴露了groupID,ArtifactID,版本等的getters的实现。
这是一个最新的MAVEN3示例,介绍了如何获得所有依赖关系(包括及物)以及对文件本身的访问(例如,如果您需要将路径添加到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.
}
}
}
更改Mojo中的参数是我缺少的非常重要的作品。没有它,类似以下几行:
@Parameter(defaultValue = "${project.compileClasspathElements}", readonly = true, required = true)
private List<String> compilePath;
只会返回类目录,而不是您期望的路径。
更改需求依赖性的票据和要求依赖性的重新解决方案将使您能够更改要抓取的内容的范围。这 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,您可以使用依赖关系图。它与DisporencyTreebuilder几乎相同。
这是一个例子
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();
}