com.gitee.l0km.javadocreader.ExtClassDoc Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of javadocreader9 Show documentation
Show all versions of javadocreader9 Show documentation
read comments from java source using javadoc
package com.gitee.l0km.javadocreader;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Executable;
import java.lang.reflect.Field;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.regex.Pattern;
import com.google.common.collect.Lists;
import com.gitee.l0km.aocache.annotations.AoWeakCacheable;
import com.gitee.l0km.javadocreader.internal.TypeNames;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.base.Strings;
import com.google.common.collect.Collections2;
import com.google.common.collect.HashBasedTable;
import com.google.common.collect.Maps;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.Element;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.VariableElement;
import com.sun.source.util.DocTrees;
import com.sun.source.doctree.*;
import jdk.javadoc.doclet.DocletEnvironment;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.ElementFilter;
import javax.lang.model.util.Elements;
import javax.lang.model.util.Types;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkArgument;;
public class ExtClassDoc {
public static final String NEW_LINE = System.getProperty("line.separator");
public static enum Type{
CLASS,METHOD,FIELD,NONE(0),ALL((~0));
static {
// 修改 ALL 的mask 值
int mask = 0;
for(Type v :Type.values()){
if(1 == Integer.bitCount(v.mask))mask |=v.mask;
}
try {
Field field = Type.class.getDeclaredField("mask");
field.setAccessible(true);
field.set(ALL, mask);
} catch (Exception e) {
throw new ExceptionInInitializerError(e);
}
// 检查所有组合mask值的合法性,超出范围则抛出异常
for(Type v :Type.values()){
if( Integer.bitCount(v.mask) > 1 && v != ALL){
if(((~ALL.mask)&v.mask) != 0)
throw new ExceptionInInitializerError(String.format("%s: %s,invalid mask, out of ALL scope",v.name(),
Integer.toBinaryString(v.mask)));
}
}
}
private final int mask;
Type(){
this.mask=(1<values){
// 过滤掉null元素
return null == values ? 0 :sum(Collections2.filter(values, new Predicate (){
@Override
public boolean apply(Type input) {
return null !=input;
}}).toArray(new Type[0]));
}
public static int sumOfString(Collectionvalues){
return null == values ? 0 :sum(Collections2.transform(values, new Function(){
@Override
public Type apply(String input) {
try{
return Type.valueOf(input);
}catch(Exception e){
return null;
}
}}));
}
public static ListcheckAll(int value){
ArrayList list = new ArrayList();
for(Type v:Type.values()){
if(v.check(value) && Integer.bitCount(v.mask) == 1)
list.add(v);
}
return list;
}
}
public static enum Action{
ADD,OVERWRITE,APPEND
}
public static enum AddColumn{
ACTION,SCOPE
}
final DocletEnvironment docEnv;
final TypeElement classDoc;
final Elements elementUtils;
final Types typeUtils;
final DocTrees docTrees;
/** 缩进字符串 */
private static String indent = " ";
/** 输出comment时要排除的{@link DocTree}名字,比如{@code '@throws'} */
private final Map excludeTags=Collections.synchronizedMap(new HashMap());
/** 输出comment时要添加在commentText中的内容 */
private final HashBasedTable additionalTextTable = HashBasedTable.create();
private final CommentTextRender render;
public ExtClassDoc(DocletEnvironment docEnv,TypeElement classDoc) {
super();
this.classDoc = checkNotNull(classDoc, "classDoc is null");
this.docEnv = checkNotNull(docEnv, "docEnv is null");
this.elementUtils=docEnv.getElementUtils();
this.typeUtils=docEnv.getTypeUtils();
this.docTrees = docEnv.getDocTrees();
this.render = new CommentTextRender();
}
/**
* 如果两个类型字符串匹配,返回{@code true},否则返回{@code false}
* @param docType
* @param type
*/
@AoWeakCacheable
private boolean equalType(TypeMirror docType,java.lang.reflect.Type type) {
String typeName = TypeNames.getTypeName(type).replaceAll("\\s+", "");
return typeName.equals(docType.toString().replaceAll("\\s+", ""));
}
/**
* 如果两个类型字符串匹配,返回{@code true},否则返回{@code false}
* @param typeElement
* @param clazz
*/
@AoWeakCacheable
private boolean equalType(TypeElement typeElement,Class> clazz) {
String typeName = TypeNames.getTypeName(clazz);
return typeName.equals(typeElement.getQualifiedName().toString());
}
/**
* 检查两个方法对象的签名是否匹配
* @param member
* @param doc
* @return 不匹配返回 {@code false} ,匹配返回 {@code true}
*/
private boolean match(Member member, Element doc) {
if (!member.getName().equals(doc.getSimpleName().toString())){
return false;
}
if(member instanceof Field) {
return true;
}
checkArgument(member instanceof Executable,"INVALID member type %s,Method or Constructor required",member.getClass().getSimpleName());
java.lang.reflect.Type[] paramTypes = ((Executable)member).getGenericParameterTypes();
checkArgument(doc instanceof ExecutableElement,"INVALID doc type %s,ExecutableElement required",doc.getClass().getSimpleName());
List extends VariableElement> parameters = ((ExecutableElement)doc).getParameters();
if (paramTypes.length != parameters.size()) {
return false;
}
for (int i = 0; i < paramTypes.length; ++i) {
if(!equalType(parameters.get(i).asType(),paramTypes[i])) {
return false;
}
}
return true;
}
/**
* 在{@link TypeElement}中查找与 {@link Method} 匹配的{@link ExecutableElement}
* 如果没有在当前方法上找到注释且是重写方法,则尝试向上父类查找父类方法
* @param method
* @return 没有找则返回{@code null}
* @see #getMemberDoc(TypeElement, Member)
*/
public ExecutableElement getMethodDoc(Method method) {
ExecutableElement doc = (ExecutableElement) getMemberDoc(classDoc,method);
while(null != doc && Strings.isNullOrEmpty(elementUtils.getDocComment(doc))){
// 如果没有注释,向上父类查找被重写的方法
doc = findMethodsInSuperClass(doc);
}
return doc;
}
private ExecutableElement findMethodsInSuperClass(ExecutableElement methodDoc) {
TypeMirror typeMirror = ((TypeElement) methodDoc.getEnclosingElement()).getSuperclass();
return findMethodsInSuperClass(typeMirror,methodDoc);
}
private ExecutableElement findMethodsInSuperClass(TypeMirror superclass, ExecutableElement method) {
if (null == superclass || superclass.getKind().isPrimitive() || superclass.toString().equals("java.lang.Object")) {
return null; // 到达根类
}
TypeElement superClassElement = (TypeElement) typeUtils.asElement(superclass);
List extends Element> enclosedElements = superClassElement.getEnclosedElements();
for (Element element : enclosedElements) {
if (element instanceof ExecutableElement) {
ExecutableElement superMethod = (ExecutableElement) element;
// 检查该方法是否重写
if (elementUtils.overrides(method,superMethod, (TypeElement) method.getEnclosingElement())) {
return superMethod;
}
}
}
// 递归查找超类
return findMethodsInSuperClass(superClassElement.getSuperclass(), method);
}
/**
*
* [递归]在{@link TypeElement}中递归查找与method匹配的{@link Element}对象
* @see #findMember(TypeElement, Member)
*/
private Element getMemberDoc(TypeElement classDoc,Member member) {
if (null == classDoc || null == member){
return null;
}
Element matched = findMember(classDoc, member);
if(matched == null){
return getMemberDoc((TypeElement) typeUtils.asElement(classDoc.getSuperclass()), member);
}
return matched;
}
/**
* 在{@link TypeElement}中查找与 {@link Executable} 匹配的{@link ExecutableElement}
* @param executable executable
* @return 没有找则返回{@code null}
* @see #getMemberDoc(TypeElement, Member)
*/
public ExecutableElement getExecutableMemberDoc(Executable executable) {
return (ExecutableElement) getMemberDoc(classDoc,executable);
}
/**
* 在{@link TypeElement}中查找与 {@link Member} 匹配的{@link Element}
* @param member member
* @return 没有找则返回{@code null}
* @see #getMemberDoc(TypeElement, Member)
*/
public Element getMemberDoc(Member member) {
return getMemberDoc(classDoc,member);
}
/**
* 在{@link TypeElement}中查找指定方法或构造方法的参数名
* @param member Method or Constructor
* @return 参数名列表,找不到返回null
*/
public String[] getParamerNames(Member member) {
ExecutableElement memberDoc = getExecutableMemberDoc((Executable)member);
if(memberDoc == null){
return null;
}
List extends VariableElement> parameters = memberDoc.getParameters();
String[] names = new String[parameters.size()];
for(int i = 0; i < names.length; ++i){
names[i] = parameters.get(i).getSimpleName().toString();
}
return names;
}
/**
* 在{@link TypeElement}中递归查找与name匹配的{@link VariableElement}
* @param classDoc
* @param name field name
* @return 没有找则返回{@code null}
*/
private VariableElement getFieldDoc(TypeElement classDoc, String name) {
if (null == classDoc || null == name) {
return null;
}
Optional opt = ElementFilter.fieldsIn(classDoc.getEnclosedElements()).stream()
.filter(e -> e.getSimpleName().contentEquals(name)).findFirst();
if (opt.isPresent()) {
return opt.get();
}
TypeMirror superClass = classDoc.getSuperclass();
return getFieldDoc(null == superClass ? null : (TypeElement) typeUtils.asElement(superClass), name);
}
/**
* 在{@link TypeElement}中查找与name匹配的{@link VariableElement}
* @param name field name
* @return 没有找则返回{@code null}
*/
public VariableElement getFieldDoc(String name) {
return getFieldDoc(classDoc,name);
}
ParamTree paramTagOf(ExecutableElement methodDoc,String name){
if(null == methodDoc) {
return null;
}
if(!Strings.isNullOrEmpty(name)){
DocCommentTree docCommentTree = docTrees.getDocCommentTree(methodDoc);
return new BlockTagExtracter().extract(docCommentTree).paramTag(name);
}
return null;
}
/**
* 类注释如果有 '@deprecated' 注解则返回{@code true},否则返回{@code false}
*/
public boolean isDeprecated() {
return isDeprecated(this.classDoc) ;
}
/**
* 注释对象{@code doc} 中如果有 '@deprecated' 注解则返回{@code true},否则返回{@code false}
* @param doc
*/
public boolean isDeprecated(Element doc) {
if(null == doc) {
return false;
}
return elementUtils.isDeprecated(doc);
}
/**
* 如果{@link Member}的注释中如果有 '@deprecated' 注解则返回{@code true},否则返回{@code false}
*
* @param member
* @since 1.3.0
*/
public boolean isDeprecated(Member member) {
return isDeprecated(getMemberDoc(member));
}
/**
* 在{@link TypeElement}中查找与method匹配的{@link ExecutableElement}对象
* 没找到匹配的对象则返回{@code null}
* @param classDoc
* @param member
*/
private Element findMember(TypeElement classDoc,Member member) {
if (null == classDoc || null == member){
return null;
}
if(!equalType(classDoc,member.getDeclaringClass())) {
return null;
}
if (member instanceof Field) {
return ElementFilter.fieldsIn(classDoc.getEnclosedElements()).stream().filter(e -> match(member, e))
.findFirst().orElse(null);
} else if (member instanceof Method) {
return ElementFilter.methodsIn(classDoc.getEnclosedElements()).stream().filter(e -> match(member, e))
.findFirst().orElse(null);
} else if (member instanceof Constructor>) {
return ElementFilter.constructorsIn(classDoc.getEnclosedElements()).stream().filter(e -> match(member, e))
.findFirst().orElse(null);
} else {
throw new IllegalArgumentException(String.format(
"INVALID member type %s,Field,Method or Constructor required", member.getClass().getSimpleName()));
}
}
/**
* 输出当前类的类及方法注释信息
* @param out 输出对象
*/
public void output(PrintStream out) {
out.println(formatComment(classDoc, false));
out.println(classDoc);
for (Element e : ElementFilter.methodsIn(classDoc.getEnclosedElements()) ) {
ExecutableElement method = (ExecutableElement)e;
out.println(formatComment(method, true));
out.printf("%s%s\n", indent, method.toString());
}
}
public String output() {
ByteArrayOutputStream out = new ByteArrayOutputStream();
output(new PrintStream(out));
return out.toString();
}
private static final String commentBody = "/**" + NEW_LINE + "cmt */" + NEW_LINE;
private static final Type typeOfDoc(Object doc){
if(doc instanceof TypeElement){
return Type.CLASS;
}
if(doc instanceof ExecutableElement){
return Type.METHOD;
}
if(doc instanceof VariableElement){
return Type.FIELD;
}
throw new UnsupportedOperationException();
}
private Set select(final Type type,final Action action){
return Maps.filterValues(additionalTextTable.rowMap(), new Predicate
© 2015 - 2025 Weber Informatics LLC | Privacy Policy