文章目录
通过javadoc自定义Doclet读取Java代码注释内容
注意事项
- JDK版本:本示例使用的是JDK17,因为在JDK9后jdk.javadoc包中的类有较大变动,特此说明。
Javadoc命令的基本使用
配置好JDK环境
1.准备一下需要需要读取注释的java文件
/**
* 人员接口
*
* @author user1
*/
public interface IPerson {
/**
* 对某人说话
*
* @param otherPersonName 别人的名称
* @return 想说的话
*/
String sayHello(String otherPersonName);
}
/**
* 人员信息
* @author user1
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Person implements IPerson{
/**
* 人员名称
*/
private String name;
@Override
public String sayHello(String otherPersonName) {
String s = otherPersonName + "你好!";
System.out.println(s);
return s;
}
}
2.打开命令行工具执行javadoc命令
输入 javadoc -h 会有命令参数的提示
先尝试通过命令行生成api文档
#验证一下jdk版本
D:\test>java -version
java version "17.0.10" 2024-01-16 LTS
Java(TM) SE Runtime Environment (build 17.0.10+11-LTS-240)
Java HotSpot(TM) 64-Bit Server VM (build 17.0.10+11-LTS-240, mixed mode, sharing)
#执行生成命令
D:\test>javadoc -encoding utf-8 -private -d D:\test -classpath D:\doc\repo\org\projectlombok\lombok\1.18.28\lombok-1.18.28.jar -sourcepath D:\doc\IdeaProjects\my-doc-gen\src\main\java -subpackages com.gnem.doc
正在加载程序包com.gnem.doc的源文件...
正在构造 Javadoc 信息...
正在构建所有程序包和类的索引...
标准 Doclet 版本 17.0.10+11-LTS-240
正在构建所有程序包和类的树...
正在生成D:\test\com\gnem\doc\IPerson.html...
正在生成D:\test\com\gnem\doc\Person.html...
正在生成D:\test\com\gnem\doc\package-summary.html...
正在生成D:\test\com\gnem\doc\package-tree.html...
正在生成D:\test\overview-tree.html...
正在构建所有类的索引...
正在生成D:\test\allclasses-index.html...
正在生成D:\test\allpackages-index.html...
正在生成D:\test\index-all.html...
正在生成D:\test\index.html...
正在生成D:\test\help-doc.html...
详细分解一下命令
参数 | 说明 |
---|---|
-encoding utf-8 | 编码格式 |
-private | 显示所有类型和成员 |
-d D:\test | 文档生成的目标目录 |
-classpath D:\doc\repo\org\projectlombok\lombok\1.18.28\lombok-1.18.28.jar(使用了lombok的注解) | 依赖文件的位置 |
-sourcepath D:\doc\IdeaProjects\my-doc-gen\src\main\java | 生成文档的源文件的位置 |
-subpackages com.gnem.doc | 扫描 |
-doclet(后面会使用) | 通过替代 doclet 生成输出 |
-docletpath (后面会使用) | 类文件的位置 |
3.查看生成的API文档
进入D:\test目录打开index.html
通过自定义Doclet读取java注释
命令行方式无法自定义文档内容,可以通过重写jdk.javadoc.doclet.Doclet类的方法来实现注释内容的读取
1.创建自定义的Doclet类
@Slf4j
public class MyDoclet implements Doclet {
/**
* 执行文档读取
*
* @param args args
*/
public static void main(String[] args) {
log.info("main");
//组装命令
String[] javadocCommand =
new String[]{
"-encoding", "utf8",
"-private",
"-doclet", "com.gnem.doc.MyDoclet",//自定义MyDoclet的全限定名
"-docletpath", "相应的路径\\target\\classes",//编译后文件根路径
"-classpath", "相应的路径\\lombok-1.18.28.jar;",//所需的依赖;分割
"-sourcepath", "相应的路径\\src\\main\\java",//要读取注释的包路径
"-subpackages", "com.gnem.doc"//具体那个包
};
DocumentationTool docTool = ToolProvider.getSystemDocumentationTool();
//执行命令后会执行下面的run方法
docTool.run(System.in, System.out, System.err, javadocCommand);
}
/**
* 文档被初始化后可以读取到数据类
*
* @param environment 文档结构对象
* @return
*/
@Override
public boolean run(DocletEnvironment environment) {
log.info("run() ing...");
for (Element element : environment.getIncludedElements()) {
//打印文件名称
log.info("节点名称:{}",element.getSimpleName().toString());
}
return true;
}
//...省略其他的
}
测试看看是否可以正常读取看看控制台打印–有正常输出
2.注释解析需要重写run方法,其他的继承或实现方法可以留空
/**
* 文档被初始化后可以读取到数据类
*
* @param environment 文档结构对象
* @return
*/
@Override
public boolean run(DocletEnvironment environment) {
log.info("run() ing...");
//获取文档树
final DocTrees docTrees = environment.getDocTrees();
//遍历节点书
for (Element element : environment.getIncludedElements()) {
//节点名称
String elementName = element.getSimpleName().toString();
//节点类型
ElementKind kind = element.getKind();
String elementType = kind.toString();
//只看类文件
if (!kind.equals(ElementKind.CLASS)) {
continue;
}
//转变下节点类型
TypeElement type = TypeElement.class.cast(element);
String qualifiedName = type.getQualifiedName().toString();
log.info("---------------------Class---------------------");
log.info("节点名称:{}; 节点类型:{}; 全限定名称{}", elementName, elementType, qualifiedName);
//获取节点上的注解列表
List<? extends AnnotationMirror> annotationMirrors = element.getAnnotationMirrors();
if (!annotationMirrors.isEmpty()) {
log.info(" 注解:{}", annotationMirrors);
}
//获取当前节点的注释
DocCommentTree commentTree = docTrees.getDocCommentTree(element);
String classComment = commentTree.getFullBody().toString();
log.info(" 注释:{}", unicode2String(classComment));
List<? extends DocTree> classCommentTags = commentTree.getBlockTags();
log.info(" 注释标签:{}", classCommentTags.toString());
//获取类中元素
List<? extends Element> enclosedElements = type.getEnclosedElements();
for (Element innerElement : enclosedElements) {
//内部节点名称
String innerElementName = innerElement.getSimpleName().toString();
//内部节点类型
ElementKind innerKind = innerElement.getKind();
String innerType = innerKind.toString();
//修饰符
Set<Modifier> modifiers = innerElement.getModifiers();
DocCommentTree innerCommentTree = docTrees.getDocCommentTree(innerElement);
//只看方法和字段
if (innerKind.equals(ElementKind.METHOD)) {
//方法信息
ExecutableElement methodElement = ExecutableElement.class.cast(innerElement);
//todo 自己尝试吧!methodElement....>
log.info(" 方法:{}---{} {}", innerType, modifiers, innerElementName);
log.info(" 方法注释:{}", unicode2String(innerCommentTree.getFullBody().toString()));
} else if (innerKind.equals(ElementKind.FIELD)) {
//字段信息
String filedType = innerElement.asType().toString();
log.info(" 字段:{}---{} {} {}", innerType, modifiers, filedType, innerElementName);
log.info(" 字段注释:{}", unicode2String(innerCommentTree.getFullBody().toString()));
} else {
continue;
}
}
}
return true;
}