跳到主要内容

JEP 105:DocTree API

概括

扩展编译器树 API 以提供对 javadoc 注释内容的结构化访问。

目标

提供对 javadoc 注释的语法元素的访问。

非目标

检查 javadoc 注释中的 HTML 标记的语义格式良好性并不是目标,即根据 DTD 或类似内容检查 HTML;但是,应该可以使用 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 使用。也就是说,直到我们将各种公共 API 添加到 javac 为止,客户端和注释处理器可以通过这些 API 访问文档注释(如果他们愿意)。

这意味着文档评论有 3 种类型的客户端:

  1. 不需要注释——javac,当不需要运行注释处理器时
  2. 绝对需要注释——javadoc
  3. 可能需要注释 -- 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 字符实体,例如“&”
  • taglet,例如 {@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 将依赖于此。

影响

  • 其他 JDK 组件:javadoc
  • 兼容性:最小
  • 国际化:最小
  • 本地化:最小