JEP 105:DocTree API
概述
扩展编译器树 API,以提供对 Javadoc 注释内容的结构化访问。
目标
提供对 Javadoc 注释的语法元素的访问。
非目标
检查 javadoc 注释中的 HTML 标签是否在语义上结构良好(即,根据 DTD 或类似标准检查 HTML)并不是目标;然而,应该可以使用 API 来提供此类工具。
动机
这个 API 将支持提供新一代的文档注释工具。此类工具可以使用编译器和树 API 编写,也可以作为注解处理器编写。一个迟迟未更新的工具是旧版 DocCheck 文档工具的现代等价物,用于检查文档注释内容的简单规则和指南,并且自 Java 5 及之后的语言变更以来从未更新过。
javadoc 也可以重写为利用新的结构化文档注释对象,并能够在错误消息中使用诸如源位置之类的附加信息。HTML 解析还可以帮助 javadoc 生成有效的 XHTML。尽管 JDK 7 中的 javadoc 工作使其易于为 javadoc 自身生成的部分生成 XHTML,但 javadoc 当前尚无法检查或验证其所处理的源文件中的 doc 注释内的 XHTML 使用情况。
描述
问题(们)...
在 JDK 5 中,有一个单一的扫描器,能够根据 javadoc 的需要读取文档注释。在 JDK 6 中,代码被重构为两个扫描器,其中一个能够读取文档注释,适用于 javadoc,另一个则不能,适用于 javac。也就是说,直到我们向 javac 添加了各种公共 API,通过这些 API,客户端和注解处理器可以根据需要获取文档注释。
这意味着文档注释有 3 种类型的客户端:
- 无需注释 -- 当不需要运行注解处理器时,使用
javac
- 绝对需要注释 -- 使用
javadoc
- 可能需要注释 --
javac
公共 API 的客户端,包括由javac
运行的注解处理器
问题在于,读取和维护文档注释表的成本很高,而在第 3 类中,我们必须支持文档注释表,因为客户有可能需要它,尽管大多数人并不需要。
文档注释表的另一个问题是它的技术含量很低。它只是树节点到字符串的一个映射,其中字符串是 javadoc 所需的文档注释,这意味着每一行的开头(空白和典型的 '*')已被去除。这确实使得将文档注释中的位置与原始源文件中的位置关联起来变得非常困难,这就是为什么你没有看到任何来自 javadoc 的传统“emacs 风格”的错误消息,比如“未找到参数名称”或“异常未声明抛出”。
同样的低技术含量的文档注释表也对 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
- 兼容性:最小化
- 国际化:最小化
- 本地化:最小化