重写 CompilationUnit 时保留类型、字段和方法注释
Preserving type, field and method comment when rewriting a CompilationUnit
TL;DR:如何在基于给定类型创建新的 java 类型时保留 Javadoc、行和块注释?
长:
我正在使用 headless eclipse 将基于不需要的基础 class 的无限数量的类型 (Java classes) 批量转换为 Java 枚举类型使用 JDT 的应用程序。我的方法是根据类型信息创建一个新的EnumDeclaration
,并在初始[=53]的FieldDeclaration
(不包括serialVersionUID
)的基础上添加EnumConstantDeclaration
=] 类型。之后,我通过简单地将原始 MethodDeclaration
的克隆添加到新创建的 EnumDeclaration
的 BodyDelcaration
来添加 MethodDeclaration
(不包括构造函数)。完成后,感谢伟大的 API,这非常简单,我将执行以下操作...
// create the EnumDeclaration from the given UnwantedClass CompilationUnit
final EnumDeclaration enumTypeDeclaration = createEnumDeclaration(cu, astRoot, methodDeclarations, ast);
// Find the original UnwantedClass TypeDeclaration and replace it with the new EnumDeclaration
astRoot.accept(new ASTVisitor() {
@Override
public boolean visit(final TypeDeclaration node) {
rewriter.replace(node, enumTypeDeclaration, null);
return false;
}
});
...用新的 EnumDeclaration
替换原来的 Java class Type
。这几乎完美。唯一缺少的是原始 Java 类型的所有 Line
-、Block
- 和 JavadocComment
元素。我发现您至少可以通过以下方式检索所有 Comment
个实例:
List<Comment> comments = cu.getCommentList();
if (comments != null) {
for (Comment comment : comments) {
comment.accept(visitor);
}
}
这给了我所有的评论,但我还没有想出如何将 Comment
实例映射到 BodyDeclaration
,因为这些 Comment
实例基本上都是自由浮动的在 Source
文件上,并且仅通过 Source
文件中的 startPosition 链接。
有 getAlternateRoot
方法,但我还没有设法利用那个方法。
问题是:如何保留原始类型中的 Comment
个实例并将它们放在新类型中的正确位置?
似乎没有直接的方法来解决这个问题,因为 javadoc(或一般的注释)在 java 文件中与它们所指的实际代码没有直接关系评论。这只是开发人员的常识,我们通常将注释放在我们正在注释的代码之上。所以我采取了以下路径来解决这个问题:
- 创建一个基于起始位置的索引,它将一个整数(起始位置)映射到所谓的 CommentEntry 实例,它基本上是一个由 org.eclipse.jdt.core.dom.Comment 和实际文本组成的元组,我通过简单的子字符串提取编译单元的源字符串。
- 我访问我原来的 CompilationUnit 并检索所有相关的 ASTNode,在我的例子中它们是 Type-、Field- 和 MethodDeclaration 实例,并将它们映射到它们的起始位置。
- 现在我从 1. 遍历所有映射的 CommentEntry 位置,并将它们与映射到相同位置(来自 2. 的映射)的 ASTNode 实例相关联。结果是一张带有 ASTNode -> CommentEntry.
的地图
- 在构建我的新 EnumDeclaration 时,我从 3 查询地图。要么使用实际的 ASTNode 类型(TypeDeclaration 仅存在一次),要么使用 ASTNode 的实际实例(我使用原始 FieldDeclarations 中的属性创建 EnumConstants) ,或使用 ASTMatcher 来识别正确的 MethodDeclaration,因为我必须克隆这些以便能够将它们“复制”到新的 EnumDeclaration Body 部分。
注释的添加并不像我想象的那么简单,因为在较新的 JSL 中,您不能简单地在 javadoc 中设置注释字符串(仅在 JSL2 中支持,但在这个版本中我们没有't 枚举)。所以,我使用了以下代码:
private void setJavadoc(final BodyDeclaration bodyDeclaration, final CommentEntry commentEntry) {
final Javadoc javadoc = (Javadoc) ASTNode.copySubtree(ast, commentEntry.getComment());
final TagElement tagElement = ast.newTagElement();
final TextElement textElement = ast.newTextElement();
textElement.setText(commentEntry.getText());
tagElement.fragments().add(textElement);
javadoc.tags().add(tagElement);
bodyDeclaration.setJavadoc(javadoc);
}
如您所见,可以使用 TextElement 简单地添加实际的评论文本,即使它包含标签。为了使其完美,您可能需要对先前从源文件中提取的注释文本进行子字符串化,因为它将包含 /** 和 */.
TL;DR:如何在基于给定类型创建新的 java 类型时保留 Javadoc、行和块注释?
长:
我正在使用 headless eclipse 将基于不需要的基础 class 的无限数量的类型 (Java classes) 批量转换为 Java 枚举类型使用 JDT 的应用程序。我的方法是根据类型信息创建一个新的EnumDeclaration
,并在初始[=53]的FieldDeclaration
(不包括serialVersionUID
)的基础上添加EnumConstantDeclaration
=] 类型。之后,我通过简单地将原始 MethodDeclaration
的克隆添加到新创建的 EnumDeclaration
的 BodyDelcaration
来添加 MethodDeclaration
(不包括构造函数)。完成后,感谢伟大的 API,这非常简单,我将执行以下操作...
// create the EnumDeclaration from the given UnwantedClass CompilationUnit
final EnumDeclaration enumTypeDeclaration = createEnumDeclaration(cu, astRoot, methodDeclarations, ast);
// Find the original UnwantedClass TypeDeclaration and replace it with the new EnumDeclaration
astRoot.accept(new ASTVisitor() {
@Override
public boolean visit(final TypeDeclaration node) {
rewriter.replace(node, enumTypeDeclaration, null);
return false;
}
});
...用新的 EnumDeclaration
替换原来的 Java class Type
。这几乎完美。唯一缺少的是原始 Java 类型的所有 Line
-、Block
- 和 JavadocComment
元素。我发现您至少可以通过以下方式检索所有 Comment
个实例:
List<Comment> comments = cu.getCommentList();
if (comments != null) {
for (Comment comment : comments) {
comment.accept(visitor);
}
}
这给了我所有的评论,但我还没有想出如何将 Comment
实例映射到 BodyDeclaration
,因为这些 Comment
实例基本上都是自由浮动的在 Source
文件上,并且仅通过 Source
文件中的 startPosition 链接。
有 getAlternateRoot
方法,但我还没有设法利用那个方法。
问题是:如何保留原始类型中的 Comment
个实例并将它们放在新类型中的正确位置?
似乎没有直接的方法来解决这个问题,因为 javadoc(或一般的注释)在 java 文件中与它们所指的实际代码没有直接关系评论。这只是开发人员的常识,我们通常将注释放在我们正在注释的代码之上。所以我采取了以下路径来解决这个问题:
- 创建一个基于起始位置的索引,它将一个整数(起始位置)映射到所谓的 CommentEntry 实例,它基本上是一个由 org.eclipse.jdt.core.dom.Comment 和实际文本组成的元组,我通过简单的子字符串提取编译单元的源字符串。
- 我访问我原来的 CompilationUnit 并检索所有相关的 ASTNode,在我的例子中它们是 Type-、Field- 和 MethodDeclaration 实例,并将它们映射到它们的起始位置。
- 现在我从 1. 遍历所有映射的 CommentEntry 位置,并将它们与映射到相同位置(来自 2. 的映射)的 ASTNode 实例相关联。结果是一张带有 ASTNode -> CommentEntry. 的地图
- 在构建我的新 EnumDeclaration 时,我从 3 查询地图。要么使用实际的 ASTNode 类型(TypeDeclaration 仅存在一次),要么使用 ASTNode 的实际实例(我使用原始 FieldDeclarations 中的属性创建 EnumConstants) ,或使用 ASTMatcher 来识别正确的 MethodDeclaration,因为我必须克隆这些以便能够将它们“复制”到新的 EnumDeclaration Body 部分。
注释的添加并不像我想象的那么简单,因为在较新的 JSL 中,您不能简单地在 javadoc 中设置注释字符串(仅在 JSL2 中支持,但在这个版本中我们没有't 枚举)。所以,我使用了以下代码:
private void setJavadoc(final BodyDeclaration bodyDeclaration, final CommentEntry commentEntry) {
final Javadoc javadoc = (Javadoc) ASTNode.copySubtree(ast, commentEntry.getComment());
final TagElement tagElement = ast.newTagElement();
final TextElement textElement = ast.newTextElement();
textElement.setText(commentEntry.getText());
tagElement.fragments().add(textElement);
javadoc.tags().add(tagElement);
bodyDeclaration.setJavadoc(javadoc);
}
如您所见,可以使用 TextElement 简单地添加实际的评论文本,即使它包含标签。为了使其完美,您可能需要对先前从源文件中提取的注释文本进行子字符串化,因为它将包含 /** 和 */.