javdoc:(JDK9)VISITOR模式遍历语法树(DocCommentTree)获取代码注释中的tag(@return,@param)对象
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();
}
}
}