bigywater.tech
Java · 219

Doclet:从 Javadoc 模型生成自定义文档

javadoc 不只是生成 HTML 的工具:它的 Doclet API 让你拿到每个类、方法的签名与文档注释,做自己的检查或报表。这篇真实写一个 doclet,运行它,再与标准 doclet 的输出对比。

12 个
默认可见成员数(-private 时 15 个)
9 条
-Xdoclint:all 对示例代码的警告数
36 个
标准 doclet 生成的文件数

自己的 doclet:遍历元素

实测 · 本机执行输出
  指定的元素 1 个,被包含(文档化)的元素 5 个
  INTERFACE shop.Store 首句:商店接口。第二句话在这里。
    METHOD       find(java.lang.String)         mods=[public, abstract]   首句=按名称查找商品。
    METHOD       all()                          mods=[public, abstract]   首句=所有商品的快照。
  CLASS shop.MemStore 首句:内存实现。
    CONSTRUCTOR  MemStore()                     mods=[public]             首句=(无)
    METHOD       find(java.lang.String)         mods=[public]             首句=(无)
    METHOD       all()                          mods=[public]             首句={@inheritDoc}, 这里额外说明:返回的是副本。
    METHOD       add(shop.Item)                 mods=[public]             首句=新增商品。 @param i 商品
  CLASS shop.Item 首句:商品。参见 ,{@link Store#find(String)},。
    FIELD        price                          mods=[protected]          首句=(无)
    FIELD        MAX                            mods=[public, static, final] 首句=(无)
    CONSTRUCTOR  Item(java.lang.String)         mods=[public]             首句=创建商品。 @param name 名称
    METHOD       name()                         mods=[public]             首句=(无)
    METHOD       price()                        mods=[public]             首句=价格。
    METHOD       getPrice()                     mods=[public]             首句=[] [deprecated 标签]
  成员共 12 个,没有文档注释 5 个,带 @deprecated 标签 1 个
Loading source files for package shop...
Constructing Javadoc information...
src/shop/MemStore.java:4: warning: 没有文档注释:MemStore()
public class MemStore implements Store {
       ^
src/shop/MemStore.java:6: warning: 没有文档注释:find(java.lang.String)
    @Override public Item find(String name) { return m.get(name); }
                          ^
src/shop/Item.java:4: warning: 没有文档注释:price
    private final String name; protected int price; public static final int MAX = 100;
                                             ^
src/shop/Item.java:4: warning: 没有文档注释:MAX
    private final String name; protected int price; public static final int MAX = 100;
                                                                            ^
src/shop/Item.java:7: warning: 没有文档注释:name()
    public String name() { return name; }
                  ^
5 warnings
  (rc=0, 0.2 s)

选项与可见性

实测 · 本机执行输出
  指定的元素 1 个,被包含(文档化)的元素 5 个
    METHOD       secret()                       mods=[private]            首句=(无)
  成员共 15 个,没有文档注释 8 个,带 @deprecated 标签 1 个
  带 -minlen 5:rc=0 True
  不认识的选项 -nosuchopt:rc=1, ['    -Werror       Report an error if any warnings occur', 'error: invalid flag: -nosuchopt']

标准 doclet 与 -Xdoclint

实测 · 本机执行输出
  javadoc -Xdoclint:all:rc=0,0.4 s,生成 36 个文件,共 306 KB;html 14 个
  诊断(节选):
    src/shop/Item.java:6: warning: no @param for name
    src/shop/Item.java:9: warning: no @return
    src/shop/Item.java:11: warning: no @return
    src/shop/Store.java:16: warning: no @return
    src/shop/Item.java:4: warning: no comment
    src/shop/Item.java:4: warning: no comment
    src/shop/Item.java:7: warning: no comment
    src/shop/MemStore.java:10: warning: no @param for i
    src/shop/MemStore.java:4: warning: use of default constructor, which does not provide a comment
    9 warnings
  Item.html 里 {@link Store#find(String)} 变成了超链接: True
  Item.html 里私有方法 secret 出现了吗: False ;@Deprecated 的 getPrice 标记为 deprecated: True
  存在的索引文件: ['allclasses-index.html', 'allpackages-index.html', 'constant-values.html', 'copy.svg', 'deprecated-list.html', 'element-list', 'help-doc.html', 'index-all.html', 'index.html', 'link.svg', 'member-search-index.js', 'module-search-index.js']

注释继承

实测 · 本机执行输出
  MemStore.html 里出现「Description copied from interface」次数: 1
  MemStore.find 一节的文字: id="find(java.lang.String)"> find public   Item   find ( String  name) Description copied from interface:  Store 按名称查找商品。 Specified by: find  in interface  Store Parameters: name - 商品名 Returns: 找到的商品,
  MemStore.all 一节的文字: id="all()"> all public   List < Item >   all () 所有商品的快照。 这里额外说明:返回的是副本。 Specified by: all  in interface  Store 
  自己的 doclet 看到的 MemStore.find / all:
     METHOD find(java.lang.String) mods=[public] 首句=(无) 
     METHOD all() mods=[public] 首句={@inheritDoc}, 这里额外说明:返回的是副本。 

分步演示

Doclet
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / OpenJDK(Temurin 17.0.20、Homebrew 21.0.12 与 27,每篇注明实际用的版本);用 javac 编译、java 直接运行,需要第三方库时用 Maven 解析依赖;计时用 System.nanoTime,数字每次运行会有小幅抖动。JDK 21.0.12 的 javadoc;示例代码是自己写的 3 个小类
    • 没有验证:模块(module-info)项目的 doclet 行为、taglet 自定义块标签、doclet 输出 HTML 的主题定制、与 Maven javadoc 插件集成、JDK 17 与 27 的 Doclet API 差别、大型代码库上 javadoc 的耗时
    京ICP备2026067502号-1京公网安备11010502063487号