All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.arsframework.annotation.processor.AbstractValidateProcessor Maven / Gradle / Ivy

package com.arsframework.annotation.processor;

import java.util.Set;
import java.util.List;
import java.util.Arrays;
import java.util.Iterator;
import java.util.ArrayList;
import java.lang.annotation.Annotation;

import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.type.MirroredTypesException;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.ProcessingEnvironment;

import com.sun.source.tree.Tree;
import com.sun.tools.javac.util.Name;
import com.sun.tools.javac.util.Names;
import com.sun.tools.javac.util.Context;
import com.sun.tools.javac.util.ListBuffer;
import com.sun.tools.javac.code.Symbol;
import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.tree.TreeMaker;
import com.sun.tools.javac.api.JavacTrees;
import com.sun.tools.javac.processing.JavacProcessingEnvironment;

import com.arsframework.annotation.Ignore;

/**
 * 参数校验注解处理器抽象实现
 *
 * @author yongqiang.wu
 */
public abstract class AbstractValidateProcessor extends AbstractProcessor {
    protected Names names;
    protected Context context;
    protected TreeMaker maker;
    protected JavacTrees trees;

    @Override
    public SourceVersion getSupportedSourceVersion() {
        return SourceVersion.latest().compareTo(SourceVersion.RELEASE_8) > 0 ? SourceVersion.latest() : SourceVersion.RELEASE_8;
    }

    @Override
    public synchronized void init(ProcessingEnvironment env) {
        super.init(env);
        this.trees = JavacTrees.instance(env);
        this.context = ((JavacProcessingEnvironment) env).getContext();
        this.names = Names.instance(this.context);
        this.maker = TreeMaker.instance(this.context);
    }

    @Override
    public boolean process(Set annotations, RoundEnvironment env) {
        for (String type : this.getSupportedAnnotationTypes()) {
            try {
                Class annotation = (Class) Class.forName(type);
                for (Element element : env.getElementsAnnotatedWith(annotation)) {
                    if (element.getKind() == ElementKind.ENUM || element.getKind() == ElementKind.CLASS
                            || element.getKind() == ElementKind.INTERFACE) { // 枚举/类/接口元素
                        for (JCTree def : ((JCTree.JCClassDecl) trees.getTree(element)).defs) {
                            if (def.getKind() == Tree.Kind.METHOD && ((JCTree.JCMethodDecl) def).body != null) {
                                this.buildValidateBlock(((JCTree.JCMethodDecl) def).sym, annotation);
                            }
                        }
                    } else if ((element.getKind() == ElementKind.CONSTRUCTOR || element.getKind() == ElementKind.METHOD)
                            && Validates.lookupAnnotation(((Symbol) element).owner, annotation) == null) { // 方法元素
                        this.buildValidateBlock((Symbol.MethodSymbol) element, annotation);
                    } else if (element.getKind() == ElementKind.PARAMETER
                            && Validates.lookupAnnotation(((Symbol) element).owner, annotation) == null) { // 参数元素
                        this.buildValidateBlock((Symbol.VarSymbol) element, annotation);
                    }
                }
            } catch (ClassNotFoundException e) {
                throw new RuntimeException(e);
            }
        }
        return true;
    }

    /**
     * 判断代码逻辑是否为构造方法调用
     *
     * @param statement 代码逻辑对象
     * @return true/false
     */
    protected boolean isConstructorInvocation(JCTree.JCStatement statement) {
        if (statement instanceof JCTree.JCExpressionStatement) {
            JCTree.JCExpression expression = ((JCTree.JCExpressionStatement) statement).expr;
            if (expression instanceof JCTree.JCMethodInvocation
                    && ((JCTree.JCMethodInvocation) expression).meth.getKind() == Tree.Kind.IDENTIFIER) {
                Name name = ((JCTree.JCIdent) ((JCTree.JCMethodInvocation) expression).meth).name;
                return name == name.table.names._this || name == name.table.names._super;
            }
        }
        return false;
    }

    /**
     * 判断注解是否被忽略
     *
     * @param param      参数代码对象
     * @param annotation 注解类型
     * @return true/false
     */
    protected boolean isIgnoreAnnotation(Symbol.VarSymbol param, Class annotation) {
        Ignore ignore;
        if (annotation != Ignore.class && (ignore = Validates.lookupAnnotation(param, Ignore.class)) != null) {
            try {
                Class[] classes = ignore.value();
                if (classes.length == 0) {
                    return true;
                }
                for (Class cls : classes) {
                    if (cls == annotation) {
                        return true;
                    }
                }
            } catch (MirroredTypesException e) {
                List mirrors = e.getTypeMirrors();
                if (mirrors.isEmpty()) {
                    return true;
                }
                String name = annotation.getCanonicalName();
                for (TypeMirror mirror : mirrors) {
                    if (mirror.toString().equals(name)) {
                        return true;
                    }
                }
            }
        }
        return false;
    }

    /**
     * 构建参数校验处理代码块
     *
     * @param param      参数代码对象
     * @param annotation 注解类型
     */
    protected void buildValidateBlock(Symbol.VarSymbol param, Class annotation) {
        JCTree.JCStatement condition;
        if (!this.isIgnoreAnnotation(param, annotation) && (condition = this.buildValidateCondition(param, annotation)) != null) {
            this.appendValidateBlock((Symbol.MethodSymbol) param.owner, Arrays.asList(condition));
        }
    }

    /**
     * 构建参数校验处理代码块
     *
     * @param method     方法代码对象
     * @param annotation 注解类型
     */
    protected void buildValidateBlock(Symbol.MethodSymbol method, Class annotation) {
        if (method != null && method.params != null && !method.params.isEmpty()) {
            List conditions = new ArrayList<>(method.params.size());
            for (Symbol.VarSymbol param : method.params) {
                JCTree.JCStatement condition;
                if (!this.isIgnoreAnnotation(param, annotation) && (condition = this.buildValidateCondition(param, annotation)) != null) {
                    conditions.add(condition);
                }
            }
            if (!conditions.isEmpty()) {
                this.appendValidateBlock(method, conditions);
            }
        }
    }

    /**
     * 添加参数校验代码块
     *
     * @param method     方法代码对象
     * @param conditions 校验代码逻辑列表
     */
    private void appendValidateBlock(Symbol.MethodSymbol method, List conditions) {
        if (conditions.isEmpty()) {
            return;
        }
        JCTree.JCBlock body = trees.getTree(method).body; // 获取方法对应的方法体
        if (method.isConstructor() && this.isConstructorInvocation(body.stats.head)) { // 如果方法体存在构造方法调用则将构造方法调用代码放在第一行
            ListBuffer stats = ListBuffer.of(body.stats.head);
            Iterator iterator = body.stats.iterator();
            iterator.next();
            for (JCTree.JCStatement condition : conditions) {
                stats.append(condition);
            }
            while (iterator.hasNext()) {
                stats.append(iterator.next());
            }
            body.stats = stats.toList();
        } else { // 将参数校验代码逻辑插入到方法体开始位置
            for (int i = conditions.size() - 1; i > -1; i--) {
                body.stats = body.stats.prepend(conditions.get(i));
            }
        }
    }

    /**
     * 构建语法树参数验证条件
     *
     * @param param      参数代码对象
     * @param annotation 注解类型
     * @return 验证条件表达式对象
     */
    protected abstract JCTree.JCIf buildValidateCondition(Symbol.VarSymbol param, Class annotation);
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy