JavaDoc 编程,书写自定义的 Taglet 支持 @unmi 等
javadoc 可为我们的 Java 项目生成 API 文档,别人的应该是看得多了,自己的可能不好意思晾出来看。那 Java 源代码里的 @author, @see, @param 等应该是司空见惯了吧。除此之外我们还可以自定义自己的 tag,并让它们的内容按照我们需要的格式生成到 javadoc 文档中,或作他用。还记得没有 Maven 的时代我们是怎样用 XDoclet 生映射文件的吗?现在的 Taglet 定制想要做的事情大抵如此。
执行一下 javadoc 命令看看,一堆的参数可以指定,又有学问在里头,且看:
-tag <name>:<locations>:<header> Specify single argument custom tags
-taglet The fully qualified name of Taglet to register
-tagletpath The path to Taglets
和
-doclet <class> Generate output via alternate doclet
-docletpath <path> Specify where to find doclet class files
关于 doclet 部份这儿暂且不说,单讲 tag 部分的东西。
对于自定义 tag,简单的时候,用参数 -tag 都可以不写自己的 taglet 类,例如有这样一个代码:
上面使用了 @document 自定义 tag,要为它生成文档,可以用命令:
javadoc -tag document:a:Document: *.java
于是生成的 javadoc 文档中有了:

-tag 参数的 name, header 部分一对照就知道了,中间那个 location 参数代表修饰谁的注释要被解析,取值有:
上面的 -tag 为 @document 生成的 HTML 是:
如果我们要为前面的 @document 生成更具表现力说明,或是另有企图 -- 如提取 @document 后的内容生成自己的外部文件中,那现在就得让 Taglet 登场了。从 DocumentTaglet 代码开始,它需要实现 com.sun.tools.doclets.Taglet 接口,要实现它所有的方法。里面有一片的 inField(),inMethod() 等方法,若返回 true 则表示这个标签可作用于这个位置上。
那什么是 isInlineTag() 呢,下面这样写的注释就是 Inline Tag: 用大括号括起来的就是 Inline tag,这时取的 tag.text() 就只是 "help" 了。你自己决定 isInlineTag() 方法返回 true 还是 false 吧。
还有那个注册方法,需 Taglet 接口中没有,但却是一定要写的,方法原型是:
public static void register(Map<String, Taglet> tagletMap),用来注册要用到的所有 Taglet, 也就是可在此一个个指定什么 tag 由哪一个类来处理。其实这里的 DocumentTaglet 可不实现 Taglet, javadoc -taglet 指定为这个类后所要做的工作就是执行该类的 register(Map<String, Taglet> tagletMap) 方法,至于后面碰到了某个 tag 时才真正去调用对应 Taglet 类的 toString 方法。
也就是说在这个 register 方法中可以同时注册多个 Taglet 类实例。这种情况下把现在的 DocumentTaglet 更名为 CustomTags 意义就更准确些。
关键是那两个 toString() 方法,它的返回值就是要交给 javadoc 显示出来的内容,文章要在这儿做。
把重要的代码前移了,因为用到了 tools.jar 包,所以编译时需把 JDK 目录中的 tools.jar 加到 classpath 上去。实际测试中不管为一个方法写一个还是多个 @document 注释,javadoc 都是直接命中 toString(Tag[] tags) 方法。
要是想在 toString(Tag[] tags) 方法中得到被注释的元素的信息,就从 Tag 类型出发,tag.holder() 得到一个 Doc,对应注释的位置,它可能是一个 MethodDoc, ClassDoc, FieldDoc, PackageDoc 等,所以当前被注释元素的信息便可由此而得。
在假设编译后的 DocumentTaglet.class 文件在 c:/javadoc_taglet/bin/cc/unmi/taglet 目录下,你可以用下面的命令为前面那个 TestJavaDocTag.java 生成 javadoc 文档:
javadoc -taglet cc.unmi.taglet.DocumentTaglet -tagletpath c:/javadoc_taglet/bin
生成的 javadoc 的效果就是, @document 的值提取出来,并渲染为红色字体显示:

我们在生成 javadoc 时,会得到提示:
Note: Custom tags that could override future standard tags: @document. To avoid
potential overrides, use at least one period character (.) in custom tag names.
那是 javadoc 怕 @document 会与别人重复,希望你能加个命名空间,如写成 @unmi.document 这样子。
tools.jar 中还有另外一个 Taglet(com.sun.tools.doclets.internal.toolkit.taglets.Taglet) 接口,尚不知作用何的,Doclet 吗?接着有空也看看 -doclet 参数的应用定制。
参考:1. javadoc - The Java API Documentation Generator
2. Taglet Overview
3. Javadoc Programming
4. Taglets Collection 永久链接 https://yanbin.blog/javadoc-programming-customize-taglet/, 来自 隔叶黄莺 Yanbin's Blog
[版权声明]
本文采用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 进行许可。
执行一下 javadoc 命令看看,一堆的参数可以指定,又有学问在里头,且看:
-tag <name>:<locations>:<header> Specify single argument custom tags
-taglet The fully qualified name of Taglet to register
-tagletpath The path to Taglets
和
-doclet <class> Generate output via alternate doclet
-docletpath <path> Specify where to find doclet class files
关于 doclet 部份这儿暂且不说,单讲 tag 部分的东西。
对于自定义 tag,简单的时候,用参数 -tag 都可以不写自己的 taglet 类,例如有这样一个代码:
1public class TestJavaDocTag {
2
3 /**
4 * @param args input command arguments
5 * @document help
6 * yourself
7 */
8 public static void main(String[] args) {
9
10 }
11}上面使用了 @document 自定义 tag,要为它生成文档,可以用命令:
javadoc -tag document:a:Document: *.java
于是生成的 javadoc 文档中有了:

-tag 参数的 name, header 部分一对照就知道了,中间那个 location 参数代表修饰谁的注释要被解析,取值有:
X (disable tag)a (all)o (overview)p (packages)t (types, that is classes and interfaces)c (constructors)m (methods)f (fields)上面的 -tag 为 @document 生成的 HTML 是:
1<b>Document:</b></dt>
2 <dd>help
3 yourself</dd>如果我们要为前面的 @document 生成更具表现力说明,或是另有企图 -- 如提取 @document 后的内容生成自己的外部文件中,那现在就得让 Taglet 登场了。从 DocumentTaglet 代码开始,它需要实现 com.sun.tools.doclets.Taglet 接口,要实现它所有的方法。里面有一片的 inField(),inMethod() 等方法,若返回 true 则表示这个标签可作用于这个位置上。
那什么是 isInlineTag() 呢,下面这样写的注释就是 Inline Tag: 用大括号括起来的就是 Inline tag,这时取的 tag.text() 就只是 "help" 了。你自己决定 isInlineTag() 方法返回 true 还是 false 吧。
1/**
2 * Inline: {@document help} yourself
3 */
4public static void main(String[] args) {
5
6}还有那个注册方法,需 Taglet 接口中没有,但却是一定要写的,方法原型是:
public static void register(Map<String, Taglet> tagletMap),用来注册要用到的所有 Taglet, 也就是可在此一个个指定什么 tag 由哪一个类来处理。其实这里的 DocumentTaglet 可不实现 Taglet, javadoc -taglet 指定为这个类后所要做的工作就是执行该类的 register(Map<String, Taglet> tagletMap) 方法,至于后面碰到了某个 tag 时才真正去调用对应 Taglet 类的 toString 方法。
也就是说在这个 register 方法中可以同时注册多个 Taglet 类实例。这种情况下把现在的 DocumentTaglet 更名为 CustomTags 意义就更准确些。
关键是那两个 toString() 方法,它的返回值就是要交给 javadoc 显示出来的内容,文章要在这儿做。
1package cc.unmi.taglet;
2
3import java.util.Map;
4import com.sun.javadoc.Tag;
5import com.sun.tools.doclets.Taglet;
6
7public class DocumentTaglet implements Taglet {
8
9 private static final String NAME = "document";
10 private static final String HEADER = "Document:";
11
12 @Override
13 public String getName() {
14 return NAME;
15 }
16
17 @Override
18 public String toString(Tag[] tags) {
19 StringBuilder result = new StringBuilder();
20 for (Tag tag : tags) {
21 result.append("\n<dt><b>" + HEADER + "</b>");
22 result.append("<dd style='color:red'>" + tag.text() + "</dd>");
23 }
24 //or do anything here ......
25 return result.toString();
26 }
27
28 @Override
29 public String toString(Tag tag) {
30 return toString(new Tag[] { tag });
31 }
32
33 public static void register(Map<String, Taglet> tagletMap) {
34 DocumentTaglet tag = new DocumentTaglet();
35 Taglet t = (Taglet) tagletMap.get(tag.getName());
36 if (t != null) {
37 tagletMap.remove(tag.getName());
38 }
39 tagletMap.put(tag.getName(), tag);
40 }
41
42 @Override
43 public boolean inConstructor() {
44 return false;
45 }
46
47 @Override
48 public boolean inField() {
49 return false;
50 }
51
52 @Override
53 public boolean inMethod() {
54 return true;
55 }
56
57 @Override
58 public boolean inOverview() {
59 return false;
60 }
61
62 @Override
63 public boolean inPackage() {
64 return false;
65 }
66
67 @Override
68 public boolean inType() {
69 return false;
70 }
71
72 @Override
73 public boolean isInlineTag() {
74 return true;
75 }
76}把重要的代码前移了,因为用到了 tools.jar 包,所以编译时需把 JDK 目录中的 tools.jar 加到 classpath 上去。实际测试中不管为一个方法写一个还是多个 @document 注释,javadoc 都是直接命中 toString(Tag[] tags) 方法。
要是想在 toString(Tag[] tags) 方法中得到被注释的元素的信息,就从 Tag 类型出发,tag.holder() 得到一个 Doc,对应注释的位置,它可能是一个 MethodDoc, ClassDoc, FieldDoc, PackageDoc 等,所以当前被注释元素的信息便可由此而得。
在假设编译后的 DocumentTaglet.class 文件在 c:/javadoc_taglet/bin/cc/unmi/taglet 目录下,你可以用下面的命令为前面那个 TestJavaDocTag.java 生成 javadoc 文档:
javadoc -taglet cc.unmi.taglet.DocumentTaglet -tagletpath c:/javadoc_taglet/bin
生成的 javadoc 的效果就是, @document 的值提取出来,并渲染为红色字体显示:

我们在生成 javadoc 时,会得到提示:
Note: Custom tags that could override future standard tags: @document. To avoid
potential overrides, use at least one period character (.) in custom tag names.
那是 javadoc 怕 @document 会与别人重复,希望你能加个命名空间,如写成 @unmi.document 这样子。
tools.jar 中还有另外一个 Taglet(com.sun.tools.doclets.internal.toolkit.taglets.Taglet) 接口,尚不知作用何的,Doclet 吗?接着有空也看看 -doclet 参数的应用定制。
参考:1. javadoc - The Java API Documentation Generator
2. Taglet Overview
3. Javadoc Programming
4. Taglets Collection 永久链接 https://yanbin.blog/javadoc-programming-customize-taglet/, 来自 隔叶黄莺 Yanbin's Blog
[版权声明]
本文采用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 进行许可。