java反射 - 解析注释

使用 swagger 的时候,产生了这样一个想法:代码中本身就有一套注释,为啥还要引入一套注解,这不是在做重复的工作么?

要完成这个工作,需要用到 tools.jar,不需要下载,从 jdk 中复制即可。

优点:

  1. 解决了代码与 swagger 之间的耦合,正常写代码注释即可,降低了学习成本。

缺点:

  1. java 文件编译成 class 文件之后,代码中的注释会被清空,所以只能在前期使用。
  2. 正式部署项目的时候,还要删除 tools.jar 包,不然会被检测出一些系统漏洞。
<!--JavaDoc-->
<dependency>
    <groupId>com.sun.javadoc</groupId>
    <artifactId>com.sun.javadoc</artifactId>
    <scope>system</scope>
    <systemPath>${project.basedir}/src/main/resources/lib/tools.jar</systemPath>
</dependency>

使用方式与 java 反射十分类似,下列代码展示了最基础的使用。

package cn.seaboot.plugin;

import cn.seaboot.admin.bean.core.SysAppInfo;
import cn.seaboot.common.core.CommonUtils;
import com.sun.javadoc.*;

import java.io.File;
import java.io.FileNotFoundException;
import java.util.Arrays;

/**
 * 注释解析依赖于 .class 文件和 .java 文件,因此参数中需要文件存放路径,
 * 其余代码与 java 反射非常一致
 *
 * @author Mr.css
 * @date 2020-07-28 14:24
 */
public class JavaApi {
    private static RootDoc rootDoc;
    /**
     * class 文件的地址
     */
    private static String classPath = "D:/seaboot/admin/target/classes";
    /**
     * 工程路径,用于拼接 java 文件的地址
     */
    private static String projectPath = System.getProperty("user.dir") + "/";
    /**
     * java 文件路径
     */
    private static String javaPath = "src/main/java/";

    /**
     * 要实现注释解析,必须存在这个函数,算是约定俗成的写法
     * a interface of javadoc
     *
     * @param rootDoc rootDoc
     * @return true
     * @see com.sun.tools.javadoc.Main
     */
    public static boolean start(RootDoc rootDoc) {
        JavaApi.rootDoc = rootDoc;
        return true;
    }

    public static String getClassPath() {
        return classPath;
    }

    public static void setClassPath(String classPath) {
        JavaApi.classPath = classPath;
    }

    public static String getProjectPath() {
        return projectPath;
    }

    public static void setProjectPath(String projectPath) {
        JavaApi.projectPath = projectPath;
    }

    public static String getJavaPath() {
        return javaPath;
    }

    public static void setJavaPath(String javaPath) {
        JavaApi.javaPath = javaPath;
    }

    public static RootDoc getRootDoc(Class clazz) throws FileNotFoundException {
        String filePath = projectPath + javaPath + clazz.getPackage().getName().replace(".", "/")
            + "/" + clazz.getSimpleName() + ".java";
        File file = new File(filePath);
        if (!file.exists()) {
            throw new FileNotFoundException("java file not found: " + filePath);
        }
        com.sun.tools.javadoc.Main.execute(new String[]{"-doclet",
            JavaApi.class.getName(),
            "-encoding", "utf-8", "-classpath",
            classPath,
            filePath});
        return rootDoc;
    }

    public static String getSignature(MethodDoc methodDoc) {
        Parameter[] parameters = methodDoc.parameters();
        if (CommonUtils.isEmpty(parameters)) {
            return null;
        } else {
            StringBuilder sb = new StringBuilder();
            sb.append(parameters[0].type());
            for (int i = 1; i < parameters.length; i++) {
                sb.append(",").append(parameters[i].type());
            }
            return sb.toString();
        }
    }

    public static String getSimpleSignature(MethodDoc methodDoc) {
        Parameter[] parameters = methodDoc.parameters();
        if (CommonUtils.isEmpty(parameters)) {
            return null;
        } else {
            StringBuilder sb = new StringBuilder();
            sb.append(parameters[0].type().simpleTypeName());
            for (int i = 1; i < parameters.length; i++) {
                sb.append(",").append(parameters[i].type().simpleTypeName());
            }
            return sb.toString();
        }
    }

    public static String getParameterText(MethodDoc methodDoc, String name) {
        ParamTag[] paramTags = methodDoc.paramTags();
        for (ParamTag tag : paramTags) {
            if (tag.parameterName().equals(name)) {
                return tag.parameterComment();
            }
        }
        return null;
    }

    public static void getApi(Class clazz) throws FileNotFoundException {
        RootDoc rootDoc = getRootDoc(clazz);
        for (ClassDoc classDoc : rootDoc.classes()) {
            System.out.println(classDoc.commentText());
            System.out.println(Arrays.toString(classDoc.methods()));
        }
    }

    public static void main(String[] args) throws FileNotFoundException {
        getApi(SysAppInfo.class);
    }
}

//异常注解,对应@throws
//methodDoc.throwsTags()

//参考注解,对应@see
//methodDoc.seeTags()

//获取返回值注解,对应于@return
//methodDoc.tags("@return");

//获取全部的 method 参数类型,存在函数重载的场合,函数名与参数类型,才能共同确认唯一 Method
//methodDoc.signature()

//获取返回值类型,与 java 反射同
//methodDoc.returnType()

//获取完整的注释(遇到无法解析的,可以手动解析,包含method注解,param注解,return注解...)
//methodDoc.getRawCommentText()

//获取方法注解
//methodDoc.commentText()

//获取全部注解
//methodDoc.tags();

//获取参数注解
//methodDoc.paramTags()
//ParamTag[] paramTags = methodDoc.paramTags();
//for(ParamTag paramTag: paramTags){
//    System.out.println(paramTag.isTypeParameter());
//    System.out.println(paramTag.parameterComment());
//    System.out.println(paramTag.parameterName());
//}

//暂无详细资料
//methodDoc.typeParamTags();

//获取第一句注解,与methodDoc.commentText()同
//methodDoc.firstSentenceTags()

//暂无详细资料,与methodDoc.commentText()同
//methodDoc.inlineTags();

//                Parameter[] parameters = methodDoc.parameters();
//                for (Parameter parameter : parameters) {
//                    System.out.println(parameter.toString());
//                    AnnotationDesc[] annotations = parameter.annotations();
//                    for (AnnotationDesc annotationDesc: annotations){
//                        System.out.println("-----" + annotationDesc.annotationType().getRawCommentText());
//                    }
//                }

posted on 2021-07-27 19:25  疯狂的妞妞  阅读(613)  评论(0编辑  收藏  举报

导航