如何用OpenRewrite在方法后添加单行注释?
需求
为带有Lombok @Generated注解的方法添加Parasoft Jtest抑制检测的单行注释,目标代码如下:
class FooBar { // parasoft-begin-suppress ALL @Generated public String hello() { return "Hello from com.yourorg.FooBar!"; } //parasoft-end-suppress ALL }
已完成的尝试
发现JavaParser会拆分行尾单行注释,因此采用OpenRewrite规则,已成功在注解前添加注释,代码如下:
public class JtestSuppressDelombokVisitor extends JavaIsoVisitor<ExecutionContext> { @Override public MethodDeclaration visitMethodDeclaration(MethodDeclaration methodDecl, ExecutionContext context) { boolean hasGeneratedAnnotation = methodDecl.getLeadingAnnotations().stream() .anyMatch(annotation -> annotation.getType().toString().equals("lombok.Generated")); Iterator<Comment> it = methodDecl.getPrefix().getComments().iterator(); boolean alreadyHasSuppressComment = false; while (it.hasNext()) { Comment comment = it.next(); PrintOutputCapture<String> p = new PrintOutputCapture<String>(""); comment.printComment(this.getCursor(), p); if (p.out.toString().matches(".*parasoft-begin-suppress\\sALL.*")) { alreadyHasSuppressComment = true; break; } } if (hasGeneratedAnnotation && !alreadyHasSuppressComment) { String methodDeclWhitespace = methodDecl.getPrefix().getWhitespace(); if (methodDecl.getPrefix().getComments().size() == 0) { methodDecl = methodDecl.withComments(Arrays.asList(new TextComment(false, "parasoft-begin-suppress ALL", methodDeclWhitespace, Markers.EMPTY))); } else { methodDecl.getPrefix().getComments().add(new TextComment(false, "parasoft-begin-suppress ALL", methodDeclWhitespace, Markers.EMPTY)); } return methodDecl; } return methodDecl; } }
遇到的问题
无法在方法后添加//parasoft-end-suppress ALL注释,尝试三种方式均失败:
- 使用JavaTemplate添加注释:代码执行后无任何内容添加
final JavaTemplate endSuppressCommentTemplate = JavaTemplate.builder(this::getCursor, "// parasoft-end-suppress ALL").build(); methodDecl = methodDecl.withBody(methodDecl.getBody().withTemplate( endSuppressCommentTemplate, methodDecl.getBody().getCoordinates().lastStatement() ));
- 在方法体末尾添加注释:注释被添加到方法最后一行内,且重复出现在多行,还覆盖了注解前的注释
methodDecl.getBody().getEnd().getComments().add(new TextComment(false, "parasoft-end-suppress ALL", "\n", Markers.EMPTY));
生成的错误代码:
class FooBar { //parasoft-end-suppress ALL @Generated //parasoft-end-suppress ALL public String hello() { return "Hello from com.yourorg.FooBar!"; //parasoft-end-suppress ALL }
- 创建Space实例添加注释:结果与方式2完全相同
Space currentSpace = methodDecl.getBody().getEnd(); Space newSpace = Space.build(currentSpace.getWhitespace(), currentSpace.getComments()); newSpace.getComments().add(new TextComment(false, "parasoft-end-suppress ALL", "\n", Markers.EMPTY)); methodDecl = methodDecl.withBody(methodDecl.getBody().withEnd(newSpace));
问题
如何通过OpenRewrite规则在方法后(或方法结尾处)添加单行注释?
解决方法
要在方法后添加注释,需要操作方法声明的**后缀(Suffix)**而非方法体的内容。方法体的getEnd()指向的是方法体内部的结尾,而方法声明本身的后缀才是方法闭合大括号之后的区域。
修改你的visitMethodDeclaration方法,在添加开头注释的逻辑后,加入以下代码来添加结尾注释:
// 检查是否已存在结尾抑制注释 boolean hasEndSuppress = methodDecl.getSuffix().getComments().stream() .anyMatch(comment -> { PrintOutputCapture<String> p = new PrintOutputCapture<>(""); comment.printComment(getCursor(), p); return p.out.toString().contains("parasoft-end-suppress ALL"); }); if (hasGeneratedAnnotation && !hasEndSuppress) { // 获取方法后缀的现有空白符,保持格式一致 String suffixWhitespace = methodDecl.getSuffix().getWhitespace(); // 创建结尾注释 TextComment endComment = new TextComment(false, "parasoft-end-suppress ALL", suffixWhitespace.isEmpty() ? "\n " : suffixWhitespace, Markers.EMPTY); // 构建新的后缀,添加注释 Space newSuffix = Space.build(suffixWhitespace, new ArrayList<>(methodDecl.getSuffix().getComments())); newSuffix.getComments().add(endComment); // 更新方法声明的后缀 methodDecl = methodDecl.withSuffix(newSuffix); }
关键说明:
- 方法的Suffix:
methodDecl.getSuffix()对应方法闭合大括号之后的空白和注释区域,这才是我们需要添加结尾注释的位置。 - 避免重复添加:先检查后缀中是否已存在目标注释,防止重复操作。
- 格式对齐:根据现有空白符调整注释的缩进,保持代码格式一致。
完整的修改后代码:
public class JtestSuppressDelombokVisitor extends JavaIsoVisitor<ExecutionContext> { @Override public MethodDeclaration visitMethodDeclaration(MethodDeclaration methodDecl, ExecutionContext context) { boolean hasGeneratedAnnotation = methodDecl.getLeadingAnnotations().stream() .anyMatch(annotation -> annotation.getType().toString().equals("lombok.Generated")); // 检查是否已存在开头抑制注释 boolean alreadyHasSuppressComment = methodDecl.getPrefix().getComments().stream() .anyMatch(comment -> { PrintOutputCapture<String> p = new PrintOutputCapture<>(""); comment.printComment(getCursor(), p); return p.out.toString().matches(".*parasoft-begin-suppress\\sALL.*"); }); // 添加开头注释 if (hasGeneratedAnnotation && !alreadyHasSuppressComment) { String methodDeclWhitespace = methodDecl.getPrefix().getWhitespace(); TextComment beginComment = new TextComment(false, "parasoft-begin-suppress ALL", methodDeclWhitespace.isEmpty() ? "\n " : methodDeclWhitespace, Markers.EMPTY); if (methodDecl.getPrefix().getComments().isEmpty()) { methodDecl = methodDecl.withComments(Collections.singletonList(beginComment)); } else { methodDecl.getPrefix().getComments().add(beginComment); } } // 检查是否已存在结尾抑制注释 boolean hasEndSuppress = methodDecl.getSuffix().getComments().stream() .anyMatch(comment -> { PrintOutputCapture<String> p = new PrintOutputCapture<>(""); comment.printComment(getCursor(), p); return p.out.toString().contains("parasoft-end-suppress ALL"); }); // 添加结尾注释 if (hasGeneratedAnnotation && !hasEndSuppress) { String suffixWhitespace = methodDecl.getSuffix().getWhitespace(); TextComment endComment = new TextComment(false, "parasoft-end-suppress ALL", suffixWhitespace.isEmpty() ? "\n " : suffixWhitespace, Markers.EMPTY); List<Comment> suffixComments = new ArrayList<>(methodDecl.getSuffix().getComments()); suffixComments.add(endComment); Space newSuffix = Space.build(suffixWhitespace, suffixComments); methodDecl = methodDecl.withSuffix(newSuffix); } return methodDecl; } }
这段代码会正确生成你需要的目标格式:在@Generated注解上方添加开头抑制注释,在方法闭合大括号下方添加结尾抑制注释,同时避免重复添加和格式混乱。
内容的提问来源于stack exchange,提问作者SATO Yusuke
相关产品推荐
相关产品推荐

