JDK9 javadoc API获取的源码注释结构化数据中,
- TypeElement对应
java.lang.Class
- ExecutableElement对应
java.lang.reflect.Method
和java.lang.reflect.Constructor
- VariableElement对应j
ava.lang.reflect.Field
但是,JDK 9并没有提供从Java反射类型到java Doc类型的互操作。如果要想在TypeElement中获取指定方法的的注释对象,就要自己实现这个查找功能。
本文介绍如何在TypeElement中查找指定方法(Method)对应的ExecutableElement
对象
ElementFilter
javax.lang.model.util.ElementFilter
提供了一系列类型过滤方法,可以在TypeElement中查找 指定类型的元素。
示例如下:
// 查找TypeElement中所有的方法的ExecutableElement
TypeElement classDoc;
List<ExecutableElement> list = ElementFilter.methodsIn(classDoc.getEnclosedElements());
// 查找TypeElement中所有的构造方法的ExecutableElement
TypeElement classDoc;
List<ExecutableElement> list = ElementFilter.constructorsIn(classDoc.getEnclosedElements());
// 查找TypeElement中所有的字段方法的VariableElement
TypeElement classDoc;
List<VariableElement> list = ElementFilter.fieldsIn(classDoc.getEnclosedElements());
匹配方法签名
有了ElementFilter提供的过滤功能,我们现在可以获取到所有的方法的ExecutableElement
对象。
下一步就要通过方法名和参数匹配最终精确得到方法的ExecutableElement
如果是匹配方法签名的match方法实现
/**
* 如果两个类型字符串匹配,返回{@code true},否则返回{@code false}
* @param docType
* @param type
*/
private boolean equalType(TypeMirror docType,java.lang.reflect.Type type) {
String typeName = TypeNames.getTypeName(type);
return typeName.equals(docType.toString());
}
/**
* 检查两个方法对象的签名是否匹配<br>
* @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;
}
java.lang.reflect.Type[] paramTypes;
if(member instanceof Method){
paramTypes = ((Method)member).getGenericParameterTypes();
}else if(member instanceof Constructor<?>){
paramTypes = ((Constructor<?>)member).getParameterTypes();
}else{
throw new IllegalArgumentException(String.format("INVALID member type %s,Method or Constructor required",member.getClass().getSimpleName()));
}
if(!(doc instanceof ExecutableElement)) {
throw new IllegalArgumentException(String.format("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;
}
findMember
如下是在上面的准备基础上最终实现的查找方法实现:
/**
* 在{@link TypeElement}中查找与method匹配的{@link ExecutableElement}对象<br>
* 没找到匹配的对象则返回{@code null}
* @param classDoc
* @param member
*/
private Element findMember(TypeElement classDoc,Member member) {
if (null == classDoc || null == member){
return null;
}
if(!equalType(classDoc.asType(),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()));
}
}
完整代码
完整代码参见码云仓库:https://gitee.com/l0km/javadocreader9/blob/master/src/main/java/gu/doc/ExtClassDoc.java
相关文章
《javadoc:jdk 9通过javadoc API读取java源码中的注释信息(comment)》
《javdoc:(JDK9)VISITOR模式遍历语法树(DocCommentTree)获取代码注释中的tag(@return,@param)对象》