如何在插件中访问 Maven 的依赖层次结构
Posted
技术标签:
【中文标题】如何在插件中访问 Maven 的依赖层次结构【英文标题】:How to get access to Maven's dependency hierarchy within a plugin 【发布时间】:2010-12-02 07:06:48 【问题描述】:在我的插件中,我需要处理依赖层次结构并获取有关每个依赖项以及是否被排除的信息(groupId、artifactId、版本等)。最好的方法是什么?
【问题讨论】:
如果您碰巧需要为任意工件执行此操作,同时尊重父 POM、排除等,check this approach 【参考方案1】:依赖插件具有完成大部分工作的tree goal。它使用DependencyTreeBuilder
处理MavenProject
,这将返回一个DependencyNode
,其中包含有关已解析依赖项(及其传递依赖项)的分层信息。
您可以直接从 TreeMojo 复制大部分代码。它使用CollectingDependencyNodeVisitor
遍历树并生成所有节点的List
。
您可以通过调用getArtifact()
访问该节点的Artifact
,然后根据需要获取工件信息。要获取排除原因,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();
【讨论】:
+1 非常好,谢谢!但是,sn-p 包含一个小错误: List nodes = visitor.getNodes();在 for 循环之上。 其中大部分在 Maven3 中已被弃用。有人愿意用 Maven3(未弃用)解决方案进行更新吗? 哪些依赖项描述了所有这些类?【参考方案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、版本等的 getter。
【讨论】:
+1 如果您需要获取所有 已解决 依赖项,这是一个比我更简单的解决方案,但如果您想了解有关排除的依赖项的信息,您需要的不仅仅是这个 该死,你是对的,我错过了关于排除依赖项的要点。所以这并不能回答 OP 问题。 是的,我毕竟是依赖项,所以我可以报告为什么不包括在内,不过感谢您提供的信息 在 Maven 3.x 中getDependencies()
不返回传递的 deps
在 Maven 3.x 中,有一个 [setResolvedArtifacts][1] 方法,但是它的字段是私有的... [1] maven.apache.org/ref/3.0.3/maven-core/apidocs/org/apache/maven/…【参考方案3】:
这是一个最新的 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;
只会返回类目录,而不是您期望的路径。
将 requiresDependencyCollection 和 requiresDependencyResolution 更改为不同的值将允许您更改要抓取的范围。 maven documentation 可以提供更多细节。
【讨论】:
这是最好的答案(最新且全面)。我创建了一个帐户并回答了一些问题,这样我就可以获得足够的业力来对此进行投票。谢谢。 尽管我投票支持该答案,但似乎使用此方法无法解决二级传递依赖关系。 嗨,我怎样才能让它在我的自定义扩展中工作?有人可以看看这个问题吗?非常感谢您的帮助***.com/questions/51888672/… 如果你想让它更棒一点,请包含项目依赖项。我收到 java.lang.NoClassDefFoundError: org/eclipse/aether/RepositorySystemSession ,我无法弄清楚出了什么问题。如果我添加 eclipse aether 依赖项,我会得到 org.apache.maven.artifact.versioning.DefaultArtifactVersion.compareTo(Lorg/apache/maven/artifact/versioning/ArtifactVersion;)I java.lang.NoSuchMethodError【参考方案4】:尝试使用jcabi-aether 中的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
);
【讨论】:
嗨,在这种情况下我也可以这样做吗?感谢您的帮助***.com/questions/51888672/…【参考方案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】:Maven 3 使用以太,这里有示例: https://docs.sonatype.org/display/AETHER/Home
【讨论】:
抱歉,如果链接断开,不将内容包含在 *** 中,请投反对票 - 链接现在已损坏。 以太was disowned by Eclipse,但随后adopted by Apache! ... 这是从 Eclipse Aether 1.1.0 到 Apache Aether 1.1.1 的一次微不足道的更新;大多数情况下只是 GID。 org.apache.maven.resolver 和 maven-resolver-provider【参考方案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();
【讨论】:
pom 是什么样子的。无论我做什么,在运行我的插件时我都会得到NoClassDefFoundError
s for org/sonatype/aether
以上是关于如何在插件中访问 Maven 的依赖层次结构的主要内容,如果未能解决你的问题,请参考以下文章