通过javadoc自定义Doclet读取Java代码注释内容

通过javadoc自定义Doclet读取Java代码注释内容

注意事项

  1. 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;
    }

3.执行下main方法,看看控制台

在这里插入图片描述

关于如何通过javadoc把注释读取到内存的方法就结束到这里!。

示例代码已上传gitee,点击跳转自取!

  • 29
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值