maven plugin:在自定义插件中获取当前项目的依赖库列表

我的项目中需要在自定义maven插件中调用javadoc获取java源码的注释,就需要为了javadoc能正常解析源码,还需要源码所在项目的依赖库列表(java 9以上版本的javadoc这是必须的)作为-classpath.

方案一:dependency:build-classpath

如果在项目安装(install)阶段(phase),这个参数通过执行org.apache.maven.plugins:maven-dependency-plugin:build-classpath插件的build-classpath目标就可以实现
如下:

			<plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-dependency-plugin</artifactId><version>2.9</version><executions><execution><phase>generate-sources</phase><goals><goal>build-classpath</goal></goals><configuration><!-- 结果输出到指定的属性名 --><outputProperty>maven.compile.classpath</outputProperty></configuration></execution></executions></plugin>

maven.compile.classpath这个属性的值作为参数传递给自定义插件就可以了.示例如下:

			<plugin><!-- 自定义插件 --><groupId>com.gitee.l0km</groupId><artifactId>codegen-decorator-maven-plugin</artifactId><version>${codegen.version}</version><executions>					<execution><goals><goal>generate</goal></goals></execution></executions><configuration><!-- 引用maven-dependency-plugin插件生成的maven.compile.classpath属性值 --><classPath>${maven.compile.classpath};${project.build.outputDirectory}</classPath><!-- 省略其他配置 --></configuration></plugin>

方案二

但是方案一只能在maven的 install, package阶段生效,
如果我希望命令执行自定义插件,这时不是maven生命周期的任何一个阶段,phase为NONE,
所以不能通过执行dependency:build-classpathmaven.compile.classpath的值传递给自定义插件,所以方案一就失效了.
所以只能另想办法,
那么能不能在自定义插件中调用Maven API获取当前项目的依赖库列表生成classpath呢?
我问了AI,果然是可以的,
并且给出了代码,还挺简单:

package com.example;import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.project.MavenProject;import java.util.List;@Mojo(name = "list-dependencies", defaultPhase = LifecyclePhase.INSTALL)
public class ListDependenciesMojo extends AbstractMojo {@Parameter(defaultValue = "${project}", readonly = true, required = true)private MavenProject project;@Overridepublic void execute() throws MojoExecutionException {/** 获取项目所有依赖库列表,提取文件路径生成classpath */String classpath = project.getArtifacts().stream().map(artifact -> artifact.getFile().getAbsolutePath()).filter(file -> file != null).collect(Collectors.joining(File.pathSeparator));/** 获取输出目录 */getLog().info("classpath:"+classpath);}
}

当然还需要org.apache.maven:maven-core依赖的支持

    <dependencies><dependency><groupId>org.apache.maven</groupId><artifactId>maven-core</artifactId><version>3.6.3</version></dependency></dependencies>

上面这个方案基本的逻辑就是通过插件注入的org.apache.maven.project.MavenProject实例的getArtifacts()方法获取所有依赖库列表,生成classpath.

但是实际执行时发现getArtifacts()方法返回的永远是空.
我这才明白上面的示例代码中@Mojo注解定义的defaultPhase(默认阶段)为INSTALL,也就是说在非INSTALL,PACKAGE阶段getArtifacts()方法是不返回有效数据的.
而我的自定义插件要求运行时不依赖maven的生命周期任何阶段.也就是defaultPhase=LifecyclePhase.NONE.

在google上一通找,下面这stackoverflow上的贴子给了我灵感

《how-to-get-access-to-mavens-dependency-hierarchy-within-a-plugin》

其中一个作者的回复提示了重要信息,正是我所需要的,如下图红线圈出的部分.
在这里插入图片描述
上面这个作者在@Mojo注解中定义了requiresDependencyCollection,requiresDependencyResolution才是解决问题的关键.

于是果断修改代码,如下在@Mojo注解中增加了requiresDependencyCollection,requiresDependencyResolution定义,getArtifacts()方法就可以正常返回依赖库数据了.

package com.example;import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.project.MavenProject;import java.util.List;@Mojo(name = "list-dependencies", requiresDependencyCollection = ResolutionScope.COMPILE_PLUS_RUNTIME, requiresDependencyResolution = ResolutionScope.COMPILE_PLUS_RUNTIME)
public class ListDependenciesMojo extends AbstractMojo {@Parameter(defaultValue = "${project}", readonly = true, required = true)private MavenProject project;@Overridepublic void execute() throws MojoExecutionException {/** 获取项目所有依赖库列表,提取文件路径生成classpath */String classpath = project.getArtifacts().stream().map(artifact -> artifact.getFile().getAbsolutePath()).filter(file -> file != null).collect(Collectors.joining(File.pathSeparator));/** 获取输出目录 */getLog().info("classpath:"+classpath);}
}

requiresDependencyCollection,requiresDependencyResolution

requiresDependencyCollection,requiresDependencyResolution的含义是什么?
很幸运,关于requiresDependencyCollection,requiresDependencyResolution定义,我找到了比较完整和权威的解释,我就不多写了,直接抄中文翻译.

源自sonatype.com网站的文章《What’s in Maven 3.0 for Plugin Authors?》

访问项目依赖项(requiresDependencyResolution)

插件获取项目的整个传递依赖项集的最简单方法是 mojo 注解@requiresDependencyResolution。此注解配置了以下值之一: compile, runtime 或 test,它们表示插件感兴趣的依赖项范围。已被证明麻烦的是,运行时 Classpath 不是编译 Classpath 的超集,即提供的 scope 和 system 的依赖项不包含在运行时 Classpath 中。

现在,插件作者应该做什么来检查编译和运行时类路径的并集呢?到目前为止,答案是请求测试 Classpath,或者使用适当的 scope 过滤器以编程方式进行依赖项解析。出于这样或那样的原因,这两种方法都没有真正的吸引力。因此,我们最终在 Maven 3.0 中添加了对新注释值 compile+runtime 的支持,以确保解决 compile、runtime、provided 和 system 等范围的项目依赖关系。

需要依赖项收集(requiresDependencyCollection)

当我们进行依赖项解析时,Maven 3.0 还引入了新的注释@requiresDependencyCollection。诚然,这个新注释的名称与现有的 @requiresDependencyResolution 注释仅略有不同,但在效果方面存在相当重要的差异。

依赖项解析包括两个阶段。第一阶段是确定所有传递依赖项的坐标,第二阶段是获取这些工件的文件,这可能涉及下载它们。如果一个人只对第一阶段感兴趣,我们就来谈谈依赖集合。更详细地说,如果插件目标声明@requiresDependencyCollection编译,它可以通过 MavenProject.getArtifacts() 检查项目的所有传递编译时依赖项。但与 @requiresDependencyResolution 不同的是,返回的工件实例可能是未解析的,即没有与之关联的文件。

有未解决的工件似乎很奇怪,但让我试着勾勒出激发这一点的用例。虽然未解析的工件不能用于创建 Classpath,但它们仍然允许插件检查传递依赖项集、查找不需要的工件、检查版本等。如果这让您想起了 Maven 发布插件或 Maven Enforcer 插件,那就太好了。这些插件和其他插件通常在构建的非常早期的生命周期阶段被调用,特别是在打包任何工件甚至编译任何类之前。如果这些插件在多模块构建期间尝试解决具有项目间依赖关系的依赖关系,则它们不会成功,尚未构建的内容也无法解析。

在 Maven 2.x 中,如果所有缺失的工件都在 reactor 中,则有一个 hack 可以容忍解析错误,但它仍然会给您的构建留下一个丑陋的警告,并且有问题的插件没有满足需求。@requiresDependencyCollection 是这种情况的答案,将有助于最终解决前面提到的插件中一些长期存在的问题。因此,如果您的插件不需要实际文件,而只需要项目依赖项的坐标,那么在将 Maven 3.0 作为先决条件时,请考虑使用新注解。

总结

方案二的好处显而易见,因为插件内部就能搞定项目的依赖库,如本例中,自定义插件不再需要通过定义一个参数(classpath)从外部传递项目依赖,也不再需要在pom.xml中定义maven-dependency-plugin插件获取classpath,简化了自定义插件的使用,而且场景适应性更好.

参考资料

《how-to-get-access-to-mavens-dependency-hierarchy-within-a-plugin》
《What’s in Maven 3.0 for Plugin Authors?》

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/8084.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

linux基础2

声明 学习视频来自B站UP主泷羽sec,如涉及侵权马上删除文章 笔记的只是方便各位师傅学习知识,以下网站只涉及学习内容,其他的都与本人无关,切莫逾越法律红线,否则后果自负 一&#xff0c;linux目录简介 1&#xff0c;根目录&#xff08;/&#xff09; 根目录是Linux文件系统的…

Leecode热题100-78.子集

给你一个整数数组 nums &#xff0c;数组中的元素 互不相同 。返回该数组所有可能的 子集 &#xff08;幂集&#xff09;。 解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。 示例 1&#xff1a; 输入&#xff1a;nums [1,2,3] 输出&#xff1a;[[],[1],[2],[1,2]…

【NRM】npm镜像源地址管理

【NRM】npm镜像源地址管理 1.背景 因为公司有npm内网源地址&#xff0c;很多外网依赖拉取很慢。使用nrm管理npm的源地址&#xff0c;更方便切换使用 2.NRM是什么 nrm(npm registry manager&#xff0c;nrm )是npm的镜像源管理工具&#xff0c;有时候国外资源太慢&#xff0…

uniapp—android原生插件开发(1环境准备)

本篇文章从实战角度出发&#xff0c;将UniApp集成新大陆PDA设备RFID的全过程分为四部曲&#xff0c;涵盖环境搭建、插件开发、AAR打包、项目引入和功能调试。通过这份教程&#xff0c;轻松应对安卓原生插件开发与打包需求&#xff01; 项目背景&#xff1a; UniApp集成新大陆P…

C语言复习第9章 字符串/字符/内存函数

目录 一、字符串函数1.1 读取字符串gets函数原型Example 1.2 字符串拷贝strcpy函数原型模拟实现官方源码 1.3 求字符串长度strlen函数原型关于返回值size_与算术转换的一个易错点模拟实现:递归模拟实现:指针-指针模拟实现:暴力官方源码 1.4 字符串追加strcat函数原型注意自己给…

借助 Aspose.Words,使用 C# 从 Word 文档中删除页面

如果您正在寻找一种快速删除 Word 文档中不相关、过时或空白页的方法&#xff0c;那么您来对地方了。在这篇博文中&#xff0c;我们将学习如何使用 C# 从 Word 文档中删除页面。我们将逐步引导您完成该过程&#xff0c;提供清晰的示例&#xff0c;以帮助您以编程方式高效地从 W…

AI领域的新千禧:为你的智能助手取个趣味名字!

内容概要 随着智能助手的崛起&#xff0c;它们逐渐成为我们日常生活中不可或缺的一部分。在这个过程中&#xff0c;为这些助手取一个趣味名字显得尤为重要。一个有趣的名字不仅能让用户感到更加亲切&#xff0c;还能带来更多的互动乐趣&#xff0c;使得人与科技之间的关系更加…

大数据-205 数据挖掘 机器学习理论 - 线性回归 最小二乘法 多元线性

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; 目前已经更新到了&#xff1a; Hadoop&#xff08;已更完&#xff09;HDFS&#xff08;已更完&#xff09;MapReduce&#xff08;已更完&am…

python包管理工具pip和conda的使用对比

python包管理工具pip和conda的使用对比 总述1. pip使用2. conda注意虚拟环境之间的嵌套&#xff0c;这个会导致安装包后看不到包&#xff0c;实际是安装到了base环境里 未完待续 总述 pip相对于conda,对应包的依赖关系管理不强&#xff0c;坏处是容易造成包冲突&#xff0c;好…

考取无人机“飞手”执照,进入部队、电力、铁路、石油企业抢占优势

考取无人机“飞手”执照&#xff0c;对于希望进入部队、电力、铁路、石油企业等领域的人来说&#xff0c;确实可以抢占一定的职业优势。以下是对这一观点的详细分析&#xff1a; 一、无人机“飞手”执照的考取 1. 考取条件&#xff1a; 年满16周岁&#xff0c;初中以上文化程…

蒙特卡洛方法(MC Exploring Starts算法例子)

本文章中使用的算法和例子来源于bilibili中西湖大学赵世钰老师的【强化学习的数学原理】课程。网址&#xff1a;第5课-蒙特卡洛方法&#xff08;MC Exploring Starts算法&#xff09;_哔哩哔哩_bilibili 目录 一、算法简介 二、相关定义 1、策略评估 2、visit定义 3、epis…

【Linux】解锁操作系统潜能,高效线程管理的实战技巧

目录 1. 线程的概念2. 线程的理解3. 地址空间和页表4. 线程的控制4.1. POSIX线程库4.2 线程创建 — pthread_create4.3. 获取线程ID — pthread_self4.4. 线程终止4.5. 线程等待 — pthread_join4.6. 线程分离 — pthread_detach 5. 线程的特点5.1. 优点5.2. 缺点5.3. 线程异常…

166页PDF | 埃森哲-XX集团企业架构数字化整体规划设计方案(限免下载)

一、前言 这份报告是埃森哲为XX集团制定的企业架构数字化整体规划设计方案&#xff0c;涵盖了业务、应用、数据、技术架构设计以及信息化管控体系的构建。报告详细分析了集团的信息化现状、面临的挑战&#xff0c;并提出了相应的战略目标和管理要求。同时&#xff0c;报告还规…

Linux -- 操作系统(软件)

目录 什么是操作系统&#xff1f; 计算机的层状结构 为什么要有操作系统 操作系统到底层硬件 驱动程序 操作系统如何管理硬件&#xff1f; 操作系统到用户 系统调用接口 库函数 回到问题 什么是操作系统&#xff1f; 操作系统&#xff08;Operating System&#xf…

python爬虫之JS逆向入门,了解JS逆向的原理及用法(18)

文章目录 1. JS逆向是什么?2、如何分析加密参数并还原其加密方式?2.1 分析JS加密的网页2.2 编写python代码还原JS加密代码3、案例测试4、操作进阶(通过执行第三方js文件实现逆向)4.1 python第三方模块(execjs)4.2 调用第三方js文件完成逆向操作4.3 总结1. JS逆向是什么?…

Spring Boot2(Spring Boot 的Web开发 springMVC 请求处理 参数绑定 常用注解 数据传递 文件上传)

SpringBoot的web开发 静态资源映射规则 总结&#xff1a;只要静态资源放在类路径下&#xff1a; called /static (or /public or /resources or //METAINF/resources 一启动服务器就能访问到静态资源文件 springboot只需要将图片放在 static 下 就可以被访问到了 总结&…

1、Qt6 Quick 简介

一、Qt6 Quick 简介 1、Qt Quick简介 Qt Quick 是 Qt 6 中使用的用户界面技术的总称。它是在 Qt 4 中引入的&#xff0c;现在在 Qt 6 中进行了扩展。Qt Quick 本身是几种技术的集合&#xff1a; QML——用户界面标记语言JavaScript - 动态脚本语言Qt C - 高度可移植的增强型…

element-plus按需引入报错Components is not a function

官网文档&#xff1a;快速开始 | Element Plus webpack配置 // webpack.config.js const AutoImport require(unplugin-auto-import/webpack) const Components require(unplugin-vue-components/webpack) const { ElementPlusResolver } require(unplugin-vue-components…

【AIGC】如何通过ChatGPT轻松制作个性化GPTs应用

博客主页&#xff1a; [小ᶻZ࿆] 本文专栏: AIGC | GPTs应用实例 文章目录 &#x1f4af;前言&#x1f4af;什么是GPTsGPTs的工作原理GPTs的优势GPTs的应用前景总结 &#x1f4af;创建GPTS应用的基本流程进入GPTs创建界面方式一&#xff1a;按照引导完成生成创建GPTs方式二…

uniapp配置消息推送unipush 厂商推送设置配置 FCM 教程

说真的&#xff0c;这个 密钥文件 和 google-services.json 太难找了 现在 Firebase 已经不允许注册Cloud Messaging API (旧版)的密钥&#xff0c;所以下面这个官方的文档教程并不适用,但是大致位置可以参考 UniPush支持谷歌推送FCM配置指南 - DCloud问答 密钥文件 通过这里…