javadoc:jdk 9通过javadoc API读取java源码中的注释信息(comment)
几年前写过一博客:《java:通过javadoc API读取java源码中的注释信息(comment)》,简单介绍了通过javadoc API读取源码注释的流程。
那时还是用JDK 1.8。但是在JDK9环境下JDK 1.8的那一套API就不能用了。JDK 9提供了一套新的javadoc API实现注释代码的读取,即jdk.javadoc
模块。
本文说明如何基于jdk.javadoc
来读取源码的注释。
module-info.java
需要在你的项目module-info.java中如下添加jdk.javadoc
引用。
module you_module_name{exports you.package.name;requires transitive jdk.javadoc;
}
类型迁移
从JDK 1.8迁移到JDK 9是个挺麻烦的事儿,
下面列表出了JDK 1.8下javadoc API与JDK 9提供的类型对应表。
此表只能做为基本的参照,其实许多类型在没有完全等价的类型。
Old Type(JDK8) | New Type(JDK9) |
---|---|
AnnotatedType | javax.lang.model.type.TypeMirror |
AnnotationDesc | javax.lang.model.element.AnnotationMirror |
AnnotationDesc.ElementValuePair | javax.lang.model.element.AnnotationValue |
AnnotationTypeDoc | javax.lang.model.element.TypeElement |
AnnotationTypeElementDoc | javax.lang.model.element.ExecutableElement |
AnnotationValue | javax.lang.model.element.AnnotationValue |
ClassDoc | javax.lang.model.element.TypeElement |
ConstructorDoc | javax.lang.model.element.ExecutableElement |
Doc | javax.lang.model.element.Element |
DocErrorReporter | jdk.javadoc.doclet.Reporter |
Doclet | jdk.javadoc.doclet.Doclet |
ExecutableMemberDoc | javax.lang.model.element.ExecutableElement |
FieldDoc | javax.lang.model.element.VariableElement |
LanguageVersion | javax.lang.model.SourceVersion |
MemberDoc | javax.lang.model.element.Element |
MethodDoc | javax.lang.model.element.ExecutableElement |
PackageDoc | javax.lang.model.element.PackageElement |
Parameter | javax.lang.model.element.VariableElement |
ParameterizedType | javax.lang.model.type.DeclaredType |
ParamTag | com.sun.source.doctree.ParamTree |
ProgramElementDoc | javax.lang.model.element.Element |
RootDoc | jdk.javadoc.doclet.DocletEnvironment |
SeeTag | com.sun.source.doctree.LinkTree com.sun.source.doctree.SeeTree |
SerialFieldTag | com.sun.source.doctree.SerialFieldTree |
SourcePosition | com.sun.source.util.SourcePositions |
Tag | com.sun.source.doctree.DocTree |
ThrowsTag | com.sun.source.doctree.ThrowsTree |
Type | javax.lang.model.type.TypeMirror |
TypeVariable | javax.lang.model.type.TypeVariable |
WildcardType | javax.lang.model.type.WildcardType |
Doclet
JDK 1.8中Doclet的定义很随意,只要有一个start静态方法就可以了。如下:
public static class Doclet {public Doclet() {}public static boolean start(RootDoc root) {// 获取 javadoc根数据对象,从该根对象可以提取所有其他程序结构信息JavaDocReader.root = root;return true;}}
但JDK9中对doclet类型做接口化约束,要求doclet必须实现jdk.javadoc.doclet.Doclet
接口,示例如下:
public static class DocletExample implements jdk.javadoc.doclet.Doclet {private DocletEnvironment docEnv;@Overridepublic void init(Locale locale, Reporter reporter) {}@Overridepublic boolean run(DocletEnvironment docEnv) {// 表示单次调用doclet的操作环境。此对象可用于访问命令行上的程序结构、各种实用程序和用户指定的元素。// 对应与JDK 1.8下的RootDocthis.docEnv = docEnv;return true;}@Overridepublic String getName() {return "DocletExample";}@Overridepublic Set<? extends Option> getSupportedOptions() {return Set.of();}@Overridepublic SourceVersion getSupportedSourceVersion() {return SourceVersion.latest();}}
JavadocTool
JDK 1.8下程序执行javadoc直接调用com.sun.tools.javadoc.Main
中的main
或execute
静态方法。
在JDK 9下com.sun.tools.javadoc.Main
已经不存在了。JDK 9对JDK 命令行工具进行了统一封装为ToolProvider
接口,需要使用ToolProvider机制获取JavadocToolProvider
执行javadoc.
/** 获取 javadoc tool */
ToolProvider javadocTool = ToolProvider.findFirst("javadoc").orElseThrow();
/** 执行javadoc */
javadocTool.run(System.out,System.err,new String[] {....});
实现代码
以下是基于jdk.javadoc
实现的读取源码注释的示例代码,实现读取指定的包下的所有源码注释,并输出每个类及类成员的注解。
import org.junit.Test;
import static org.junit.Assert.*;import java.util.List;
import java.util.Locale;
import java.util.Set;
import java.util.spi.ToolProvider;import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import javax.lang.model.util.ElementFilter;
import javax.lang.model.util.Elements;
import javax.tools.Diagnostic.Kind;import com.sun.source.doctree.BlockTagTree;
import com.sun.source.doctree.DocCommentTree;
import com.sun.source.util.DocTrees;import jdk.javadoc.doclet.Doclet;
import jdk.javadoc.doclet.DocletEnvironment;
import jdk.javadoc.doclet.Reporter;/*** JDK 9的javadoc tool 调用测试* @author guyadong**/
public class JavadocToolTest {@Testpublic void testJavadocTool() {try {/** 获取 javadoc tool */ToolProvider javadocTool = ToolProvider.findFirst("javadoc").orElseThrow();int returnCode = javadocTool.run(System.out,System.err,new String[] {/** 指定自定义的 Doclet 接口实现类(全名) */"-doclet", DocletExample.class.getName(), /** 指定-doclet选项定义类名的所在的类搜索路径 */"-docletpath", DocletExample.class.getProtectionDomain().getCodeSource().getLocation().getPath(),/** --subpackages 要获取注释的包名 */"-subpackages", "net.gdface.utils",/** --sourcepath 要源码路径 */"-sourcepath","D:/j/common-java/common-base/src/main/java",/** --classpath 指定javadoc执行时搜索引用类的路径 */"-classpath","D:/j/common-java/common-base/target/classes","-encoding","utf-8"});if(0 != returnCode){System.out.printf("javadoc ERROR CODE = %d\n", returnCode);throw new IllegalStateException();}} catch (Throwable e) {e.printStackTrace();fail();}}public static class DocletExample implements Doclet {private Reporter reporter;private Elements elementUtils;@Overridepublic void init(Locale locale, Reporter reporter) {reporter.print(Kind.NOTE, "Doclet using locale: " + locale);this.reporter = reporter;}/** 输出类成员的注释 */ public void printElement(DocTrees trees, Element e) {DocCommentTree docCommentTree = trees.getDocCommentTree(e);if (docCommentTree != null) {reporter.print(Kind.NOTE, "Element " + e.getKind() + ": "+ e);// 输出对应的注解reporter.print(Kind.NOTE,elementUtils.getDocComment(e));}}@Overridepublic boolean run(DocletEnvironment docEnv) {// get the DocTrees utility class to access document commentsDocTrees docTrees = docEnv.getDocTrees();elementUtils = docEnv.getElementUtils();// 循环调用printElement输出每个类成员的注释for (TypeElement t : ElementFilter.typesIn(docEnv.getIncludedElements())) {reporter.print(Kind.NOTE, t.getKind() + ":" + t.getQualifiedName());reporter.print(Kind.NOTE, "getDocComment:"+elementUtils.getDocComment(t)); for (Element e : t.getEnclosedElements()) {printElement(docTrees, e);}}return true;}@Overridepublic String getName() {return "DocletExample";}@Overridepublic Set<? extends Option> getSupportedOptions() {Option[] options = {};return Set.of(options);}@Overridepublic SourceVersion getSupportedSourceVersion() {// support the latest releasereturn SourceVersion.latest();}}
}
完整代码
完整代码参见码云仓库:https://gitee.com/l0km/javadocreader9
参考资料
《javadoc》
《Package jdk.javadoc.doclet》
相关文章:
javadoc:jdk 9通过javadoc API读取java源码中的注释信息(comment)
几年前写过一博客:《java:通过javadoc API读取java源码中的注释信息(comment)》,简单介绍了通过javadoc API读取源码注释的流程。 那时还是用JDK 1.8。但是在JDK9环境下JDK 1.8的那一套API就不能用了。JDK 9提供了一套新的javadoc API实现注释代码的读取…...
nordic使用FDS保存数据需要注意的地方
FDS使用常见问题 大家在使用FDS模块时,经常碰到的问题有如下几种: FDS不支持掉电保护,所以在Flash操作过程中出现了掉电,FDS行为将未知OTA的时候,新固件的FDS page数目一定要等于老固件的FDS page数,否则将出现不可知行为fds_record_write或者fds_record_update后,强烈…...
docker-compose集群(单机多节点)环境搭建与使用
此方案已经经过生产环境验证,可放心大胆使用如果喜欢,欢迎点赞👍收藏❤️评论噢~ 略去 Docker 和 Docker Compose 安装部分,如果有需要的同学,可以评论,创建 docker-compose.yml 文件并配置 Nacos 集群和 M…...
从静态多态、动态多态到虚函数表、虚函数指针
多态(Polymorphism)是面向对象编程中的一个重要概念,它允许不同类的对象对同一消息做出不同的响应。多态性使得可以使用统一的接口来操作不同类的对象,从而提高了代码的灵活性和可扩展性。 一、多态的表现形式 1. 静态多态&…...

用 Pygame 实现一个乒乓球游戏
用 Pygame 实现一个乒乓球游戏 伸手需要一瞬间,牵手却要很多年,无论你遇见谁,他都是你生命该出现的人,绝非偶然。若无相欠,怎会相见。 引言 在这篇文章中,我将带领大家使用 Pygame 库开发一个简单的乒乓球…...

基于大数据可视化的化妆品推荐及数据分析系统
作者:计算机学姐 开发技术:SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等,“文末源码”。 专栏推荐:前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码 精品专栏:Java精选实战项目…...

Java项目实战II基于Java+Spring Boot+MySQL的汽车销售网站(文档+源码+数据库)
目录 一、前言 二、技术介绍 三、系统实现 四、文档参考 五、核心代码 六、源码获取 全栈码农以及毕业设计实战开发,CSDN平台Java领域新星创作者,专注于大学生项目实战开发、讲解和毕业答疑辅导。获取源码联系方式请查看文末 一、前言 在数字化时…...
数学基础 -- 微积分最优化之一个最简单的例子
微积分中的一个最简单的最优化例子 问题描述 假设你有一条长度为 10 米的栅栏,你需要围成一个矩形的鸡舍,使得围成的面积最大。求这个矩形的长和宽应是多少,以使得面积最大。 步骤 设定变量: 设矩形的长为 x x x 米࿰…...

kubernetes K8S 结合 Istio 实现流量治理
目录 1.Istio介绍? 1.1 Istio是什么? 1.2 Istio流量管理 1.2.1 熔断 1.2.2 超时 1.2.3 重试 2.Istio架构 3.istio组件详解 3.1 Pilot 3.2 Envoy 3.3 Citadel 3.4 Galley 3.5 Ingressgateway 3.5 egressgateway 扩展、k8s1.23及1.23以下版…...

Selenium with Python学习笔记整理(网课+网站持续更新)
本篇是根据学习网站和网课结合自己做的学习笔记,后续会一边学习一边补齐和整理笔记 非常推荐白月黑羽的学习网站: 白月黑羽 (byhy.net) https://selenium-python.readthedocs.io/getting-started.html#simple-usage WEB UI自动化环境配置 (推荐靠谱…...

1.随机事件与概率
第一章 随机时间与概率 1. 随机事件及其运算 1.1 随机现象 确定性现象:只有一个结果的现象 确定性现象:结果不止一个,且哪一个结果出现,人们事先并不知道 1.2 样本空间 样本空间:随机现象的一切可能基本…...
Redis结合Caffeine实现二级缓存:提高应用程序性能
本文将详细介绍如何使用CacheFrontend和Caffeine来实现二级缓存。 1. 简介 CacheFrontend: 是一种用于缓存的前端组件或服务。通俗的讲:该接口可以实现本地缓存与redis自动同步,如果本地缓存(JVM级)有数据,则直接从本…...
【LLM】Ollama:本地大模型 WebAPI 调用
Ollama 快速部署 安装 Docker:从 Docker 官网 下载并安装。 部署 Ollama: 使用以下命令进行部署: docker run -d -p 11434:11434 --name ollama --restart always ollama/ollama:latest进入容器并下载 qwen2.5:0.5b 模型: 进入 O…...
SpringBoot集成阿里easyexcel(二)Excel监听以及常用工具类
EasyExcel中非常重要的AnalysisEventListener类使用,继承该类并重写invoke、doAfterAllAnalysed,必要时重写onException方法。 Listener 中方法的执行顺序 首先先执行 invokeHeadMap() 读取表头,每一行都读完后,执行 invoke()方法…...
使用ELK Stack进行日志管理和分析:从入门到精通
在现代IT运维中,日志管理和分析是确保系统稳定性和性能的关键环节。ELK Stack(Elasticsearch, Logstash, Kibana)是一个强大的开源工具集,广泛用于日志收集、存储、分析和可视化。本文将详细介绍如何使用ELK Stack进行日志管理和分…...

前端框架对比与选择
🤖 作者简介:水煮白菜王 ,一位资深前端劝退师 👻 👀 文章专栏: 前端专栏 ,记录一下平时在博客写作中,总结出的一些开发技巧✍。 感谢支持💕💕💕 目…...

Springboot jPA+thymeleaf实现增删改查
项目结构 pom文件 配置相关依赖: 2.thymeleaf有点类似于jstlel th:href"{url}表示这是一个链接 th:each"user : ${users}"相当于foreach,对user进行循环遍历 th:if进行if条件判断 {变量} 与 ${变量}的区别: 4.配置好application.ym…...

【YashanDB知识库】yashandb执行包含带oracle dblink表的sql时性能差
本文内容来自YashanDB官网,具体内容请见https://www.yashandb.com/newsinfo/7396959.html?templateId1718516 问题现象 yashandb执行带oracle dblink表的sql性能差: 同样的语句,同样的数据,oracle通过dblink访问远端oracle执行…...

效率工具推荐 | 高效管理客服中心知识库
人工智能AI的广泛应用,令AI知识库管理已成为优化客服中心运营的核心策略之一。一个高效、易用且持续更新的知识库不仅能显著提升客服代表的工作效率,还能极大提升客户的服务体验。而高效效率工具如HelpLook,能够轻松搭建AI客服帮助中心&#…...

综合实验1 利用OpenCV统计物体数量
一、实验简介 传统的计数方法常依赖于人眼目视计数,不仅计数效率低,且容易计数错误。通常现实中的对象不会完美地分开,需要通过进一步的图像处理将对象分开并计数。本实验巩固对OpenCV的基础操作的使用,适当的增加OpenCV在图像处…...
KubeSphere 容器平台高可用:环境搭建与可视化操作指南
Linux_k8s篇 欢迎来到Linux的世界,看笔记好好学多敲多打,每个人都是大神! 题目:KubeSphere 容器平台高可用:环境搭建与可视化操作指南 版本号: 1.0,0 作者: 老王要学习 日期: 2025.06.05 适用环境: Ubuntu22 文档说…...
内存分配函数malloc kmalloc vmalloc
内存分配函数malloc kmalloc vmalloc malloc实现步骤: 1)请求大小调整:首先,malloc 需要调整用户请求的大小,以适应内部数据结构(例如,可能需要存储额外的元数据)。通常,这包括对齐调整,确保分配的内存地址满足特定硬件要求(如对齐到8字节或16字节边界)。 2)空闲…...

从WWDC看苹果产品发展的规律
WWDC 是苹果公司一年一度面向全球开发者的盛会,其主题演讲展现了苹果在产品设计、技术路线、用户体验和生态系统构建上的核心理念与演进脉络。我们借助 ChatGPT Deep Research 工具,对过去十年 WWDC 主题演讲内容进行了系统化分析,形成了这份…...

AI Agent与Agentic AI:原理、应用、挑战与未来展望
文章目录 一、引言二、AI Agent与Agentic AI的兴起2.1 技术契机与生态成熟2.2 Agent的定义与特征2.3 Agent的发展历程 三、AI Agent的核心技术栈解密3.1 感知模块代码示例:使用Python和OpenCV进行图像识别 3.2 认知与决策模块代码示例:使用OpenAI GPT-3进…...
线程同步:确保多线程程序的安全与高效!
全文目录: 开篇语前序前言第一部分:线程同步的概念与问题1.1 线程同步的概念1.2 线程同步的问题1.3 线程同步的解决方案 第二部分:synchronized关键字的使用2.1 使用 synchronized修饰方法2.2 使用 synchronized修饰代码块 第三部分ÿ…...

如何在看板中有效管理突发紧急任务
在看板中有效管理突发紧急任务需要:设立专门的紧急任务通道、重新调整任务优先级、保持适度的WIP(Work-in-Progress)弹性、优化任务处理流程、提高团队应对突发情况的敏捷性。其中,设立专门的紧急任务通道尤为重要,这能…...
【ROS】Nav2源码之nav2_behavior_tree-行为树节点列表
1、行为树节点分类 在 Nav2(Navigation2)的行为树框架中,行为树节点插件按照功能分为 Action(动作节点)、Condition(条件节点)、Control(控制节点) 和 Decorator(装饰节点) 四类。 1.1 动作节点 Action 执行具体的机器人操作或任务,直接与硬件、传感器或外部系统…...
镜像里切换为普通用户
如果你登录远程虚拟机默认就是 root 用户,但你不希望用 root 权限运行 ns-3(这是对的,ns3 工具会拒绝 root),你可以按以下方法创建一个 非 root 用户账号 并切换到它运行 ns-3。 一次性解决方案:创建非 roo…...
python爬虫:Newspaper3k 的详细使用(好用的新闻网站文章抓取和解析的Python库)
更多内容请见: 爬虫和逆向教程-专栏介绍和目录 文章目录 一、Newspaper3k 概述1.1 Newspaper3k 介绍1.2 主要功能1.3 典型应用场景1.4 安装二、基本用法2.2 提取单篇文章的内容2.2 处理多篇文档三、高级选项3.1 自定义配置3.2 分析文章情感四、实战案例4.1 构建新闻摘要聚合器…...
Java入门学习详细版(一)
大家好,Java 学习是一个系统学习的过程,核心原则就是“理论 实践 坚持”,并且需循序渐进,不可过于着急,本篇文章推出的这份详细入门学习资料将带大家从零基础开始,逐步掌握 Java 的核心概念和编程技能。 …...