javdoc:(JDK9)VISITOR模式遍历语法树(DocCommentTree)获取代码注释中的tag(@return,@param)对象

时间:2024-09-30 18:04:56
import org.junit.Test; import static org.junit.Assert.*; import java.util.List; import java.util.Locale; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.spi.ToolProvider; import javax.lang.model.SourceVersion; import javax.lang.model.element.Element; import javax.lang.model.element.TypeElement; import javax.lang.model.util.ElementFilter; import javax.lang.model.util.Elements; import javax.tools.Diagnostic.Kind; import com.sun.source.doctree.BlockTagTree; import com.sun.source.doctree.DocCommentTree; import com.sun.source.util.DocTrees; import jdk.javadoc.doclet.Doclet; import jdk.javadoc.doclet.DocletEnvironment; import jdk.javadoc.doclet.Reporter; /** * JDK 9的javadoc tool 调用测试 * @author guyadong * */ public class JavadocToolTest { @Test public void testJavadocTool() { try { /** 获取 javadoc tool */ ToolProvider javadocTool = ToolProvider.findFirst("javadoc").orElseThrow(); int returnCode = javadocTool.run(System.out,System.err,new String[] { /** 指定自定义的 Doclet 接口实现类(全名) */ "-doclet", DocletExample.class.getName(), /** 指定-doclet选项定义类名的所在的类搜索路径 */ "-docletpath", DocletExample.class.getProtectionDomain().getCodeSource().getLocation().getPath(), /** --subpackages 要获取注释的包名 */ "-subpackages", "net.gdface.utils", /** --sourcepath 要源码路径 */ "-sourcepath","D:/j/common-java/common-base/src/main/java", /** --classpath 指定javadoc执行时搜索引用类的路径 */ "-classpath","D:/j/common-java/common-base/target/classes", "-encoding","utf-8", "-Xdoclint", "none" }); if(0 != returnCode){ System.out.printf("javadoc ERROR CODE = %d\n", returnCode); throw new IllegalStateException(); } } catch (Throwable e) { e.printStackTrace(); fail(); } } public static class DocletExample implements Doclet { private Reporter reporter; private Elements elementUtils; @Override public void init(Locale locale, Reporter reporter) { reporter.print(Kind.NOTE, "Doclet using locale: " + locale); this.reporter = reporter; } public void printElement(DocTrees trees, Element e) { DocCommentTree docCommentTree = trees.getDocCommentTree(e); if (docCommentTree != null) { reporter.print(Kind.NOTE,"Element " + e.getKind() + ": " + e); reporter.print(Kind.NOTE,unicodeToString(elementUtils.getDocComment(e))); BlockTagExtracter extracter = new BlockTagExtracter(); /** 遍历 docCommentTree的所有节点 */ docCommentTree.accept(extracter,null); reporter.print(Kind.NOTE,extracter.allTags().toString()); for(String tag:extracter.allTags()) { for(BlockTagTree blockTag: extracter.tags(tag)) { reporter.print(Kind.NOTE,unicodeToString(blockTag.toString())); } } } } /** 将字符串中的unicode转义字符转为unicode字符 */ public static String unicodeToString(String unicodeStr) { Matcher matcher = Pattern.compile("\\\\u([0-9a-f]{4})").matcher(unicodeStr); StringBuilder sb = new StringBuilder(); int lastAppendPosition = 0; while (matcher.find()) { sb.append(unicodeStr, lastAppendPosition, matcher.start()); sb.append((char) Integer.parseInt(matcher.group(1), 16)); lastAppendPosition = matcher.end(); } sb.append(unicodeStr, lastAppendPosition, unicodeStr.length()); return sb.toString(); } @Override public boolean run(DocletEnvironment docEnv) { // get the DocTrees utility class to access document comments DocTrees docTrees = docEnv.getDocTrees(); elementUtils = docEnv.getElementUtils(); for (TypeElement t : ElementFilter.typesIn(docEnv.getIncludedElements())) { reporter.print(Kind.NOTE,t.getKind() + ":" + t.getQualifiedName()); if(t.getQualifiedName().toString().endsWith("ResourcePool")) { reporter.print(Kind.NOTE,"ResourcePool"); } reporter.print(Kind.NOTE,"getDocComment:"+elementUtils.getDocComment(t)); for (Element e : t.getEnclosedElements()) { printElement(docTrees, e); } } return true; } @Override public String getName() { return "DocletExample"; } @Override public Set<? extends Option> getSupportedOptions() { Option[] options = { new Option() { private final List<String> someOption = List.of( "-Xdoclint" ); @Override public int getArgumentCount() { return 1; } @Override public String getDescription() { return "Enables recommended checks for problems in Javadoc comments"; } @Override public Option.Kind getKind() { return Option.Kind.STANDARD; } @Override public List<String> getNames() { return someOption; } @Override public String getParameters() { return ""; } @Override public boolean process(String opt, List<String> arguments) { return true; } } }; return Set.of(options); } @Override public SourceVersion getSupportedSourceVersion() { // support the latest release return SourceVersion.latest(); } } }