JEP 105: DocTree API
总结
扩展编译器树 API,以提供对 javadoc 注释内容的结构化访问。
目标
提供对 javadoc 注释的语法元素的访问。
非目标
在 javadoc 注释中检查 HTML 标记的语义良好性不是目标,即不检查 HTML 是否符合 DTD 或类似要求;然而,应该可以使用 API 提供这样的工具。
动机
该 API 将使得可以提供一种新一代文档注释工具。这些工具可以使用编译器和树 API 编写,也可以编写为注解处理器。一个长期以来缺失的工具是更新的 DocCheck doclet 的等价物,用于检查文档注释的内容是否符合简单的规则和指南,而且该工具从未为 Java 5 和更高版本的语言更改进行更新。
javadoc 也可以重新编写,以利用新的结构化文档注释对象,并能够在其错误消息中使用额外的信息,如源位置。HTML 解析还可以帮助 javadoc 能够生成有效的 XHTML。虽然 JDK 7 javadoc 中的工作可以很容易地为 javadoc 自身生成部分生成 XHTML,但 javadoc 目前没有手段来检查或验证源文件的文档注释中使用的 XHTML。
描述
问题...
在 JDK 5 中,有一个单一的扫描器,能够按照 javadoc 所需读取文档注释。在 JDK 6 中,该代码被重构为两个扫描器:一个能够读取文档注释,适用于 javadoc 使用;另一个则不行,适用于 javac 使用。也就是说,在我们添加了各种 javac 公共 API 后,客户端和注解处理器可以根据需要访问文档注释。
这意味着有 3 种文档注释的客户端:
不需要注释 -- 当不需要运行注解处理器时,javac 可以不考虑文档注释
绝对需要注释 -- javadoc 需要读取文档注释
可能需要注释 -- javac 公共 API 的客户端,包括由 javac 运行的注解处理器
问题在于读取和维护文档注释表格是昂贵的,在第三种情况中,我们必须支持文档注释表格,以防客户端可能需要它,尽管大多数情况下都不需要。
另一个问题是文档注释表格非常低技术含量。它只是一种从树节点到字符串的映射,其中字符串为 javadoc 所需的文档注释,这意味着每行开头的空格和典型的 '*' 都已被剥离。这确实使得将文档注释内的位置与原始源文件内的位置相关联变得非常困难,这也是为什么你不会看到来自 javadoc 的传统“emacs-style”错误消息,例如“未找到参数名称”或“未声明所抛出的异常”。
Tree API 的客户端也可以接触到相同的低技术含量的文档注释表格。对于任何树节点,你都可以获得文档注释字符串。除此之外,就只能靠自己了。解决方法是...
首先,要升级每个编译单元中存储的文档注释表格。将
Map <JCTree,String> docComments;
替换为
Map <JCTree,JCDocComment> docComments;
JCDocComment
是 javac 内部的一个新对象,提供对文档注释字符串的延迟访问。至少它包含了文档注释在源文件中的起始位置:斜线字符的位置。
interface JCDocComment {
int getPosition();
String getComment();
}
这使得我们可以拥有可能的三种不同类型的文档注释扫描器,用于三种不同类型的客户端。对于没有注解处理器的 javac,我们继续使用标准的 Scanner
,并将 docComments
表留空,就像现在一样。对于 javadoc ,我们继续像现在一样读取文档注释,只是现在我们将它们存储在 JCDocComment
对象中。对于我们不知道是否需要文档注释的 javac ,我们只需简单地存储文档注释的起始位置。这样可以在不需要文档注释时节省存储所有文档注释文字的开销。代价是当我们需要注释时,我们需要回到源文件中恢复注释的文本。不同的策略是可行的。如果源文件中需要任何注释,我们可以扫描所有注释。请注意,我们不必扫描注释之间的源代码文本,因为我们可以获得注释的起始位置,所以我们可以跳过注释之间的文本。或者我们可以根据需要读取注释,并依靠内容缓存来免除我们为每个单独的注释读取源文件内容的工作。
下一个想法是文档注释的更好解析表示。
一个文档注释由以下组成:
- 一个初始句子
- 主要描述的其余部分
- 标签列表,每个标签后面跟着一个描述
每个这些都包含一系列碎片,每个碎片都可能是以下之一:
- 纯文本,包括来自格式不正确的碎片的字符,如
'<'
,'>'
,'&'
,'{'
等。 - HTML 起始实体,包含名称和名称 - 值对列表,例如
'<a href="Object.html">'
- HTML 结束实体,包含名称,例如
'</a>'
- HTML 字符实体,如
'&'
- 标记,例如
{@link Object}
显然,这些可以用简单的树节点层次结构建模,因此我建议创建一个新的包 com.sun.source.doccomments
来包含这些树节点的接口。它最好是与现有的 com.sun.source.tree.Tree
不同的一个独立层次结构,因此我建议创建一个新的公共超级接口 com.sun.source.doccomments.DTree
。然后,我们可以扩展 com.sun.source.util
中的实用方法,以提供对任何树节点解析过的文档注释的访问,并为任何 DTree
节点提供源位置信息。
请注意,HTML 的开始标记和结束标记被视为不同的项,以避免涉及解析 HTML 以及了解哪些标记需要关闭标记而哪些不需要的问题。那一层可以由那些需要它的应用程序在这个抽象层之上构建。
解析这些注释的成本不会很低;任何涉及词法分析和语法分析的操作都不会很低成本。因此,这是提供并使用 JCDocComment
表中描述的惰性访问文档注释的另一个原因。除此之外,现在还有一个更有趣的方法可以通过它来获取注释的 DTree
,这是不必麻烦地保留当前提供的简单字符串的另一个原因。
测试
将编写 langtools 回归测试来测试新 API。一个特定的测试将是读取和处理所有 JDK API 注释。
没有特殊的平台或硬件要求。
依赖
这项工作不依赖于其他 JEP。
预计其他 JEP 将依赖于本 JEP。
影响
- 其他 JDK 组件:javadoc
- 兼容性:最小
- 国际化:最小
- 本地化:最小