protobuf不可为空的一个解决方案

利用java的插入式注解处理器, 处理掉所有的builder类型的set方法和add方法


import com.sun.source.tree.Tree;
import com.sun.tools.javac.api.JavacTrees;
import com.sun.tools.javac.code.TypeTag;
import com.sun.tools.javac.processing.JavacProcessingEnvironment;
import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.tree.TreeMaker;
import com.sun.tools.javac.tree.TreeTranslator;
import com.sun.tools.javac.util.Context;
import com.sun.tools.javac.util.List;
import com.sun.tools.javac.util.Names;

import javax.annotation.processing.*;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import javax.tools.Diagnostic;
import java.util.Set;

@SupportedAnnotationTypes("protobuf.advice.NullReturn")
@SupportedSourceVersion(SourceVersion.RELEASE_8)
public class NullReturnProcessor extends AbstractProcessor {

    /**
     * Messager 主要是用来在编译期打log用的
     * JavacTrees 提供了待处理的抽象语法树
     * TreeMaker 封装了创建AST节点的一些方法
     * Names 提供了创建标识符的方法
     */
    private Messager messager;
    private JavacTrees trees;
    private TreeMaker treeMaker;
    private Names names;

    @Override
    public synchronized void init(ProcessingEnvironment processingEnv) {
        super.init(processingEnv);
        this.messager = processingEnv.getMessager();
        this.trees = JavacTrees.instance(processingEnv);
        Context context = ((JavacProcessingEnvironment) processingEnv).getContext();
        this.treeMaker = TreeMaker.instance(context);
        this.names = Names.instance(context);
    }

    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        Set<? extends Element> set = roundEnv.getElementsAnnotatedWith(NullReturn.class);
        set.forEach(element -> {
            JCTree jcTree = trees.getTree(element);
            jcTree.accept(new TreeTranslator() {
                @Override
                public void visitClassDef(JCTree.JCClassDecl jcClassDecl) {
                    visitAllBuilder(jcClassDecl);
                }
            });
        });

        return true;
    }

    public void visitAllBuilder(JCTree.JCClassDecl jcClassDecl) {
        final JCTree.JCExpression extending = jcClassDecl.extending;

        if (extending != null) {
            // check是否是builder
            final String extendClazz = extending.toString();
            messager.printMessage(Diagnostic.Kind.NOTE, extendClazz);
            if ("com.google.protobuf.GeneratedMessage.Builder<Builder>".equals(extendClazz)) {
                processNull(jcClassDecl);
                return;
            }
        }

        for (JCTree tree : jcClassDecl.defs) {
            if (tree.getKind().equals(Tree.Kind.CLASS)) {
                visitAllBuilder(((JCTree.JCClassDecl) tree));
            }
        }
    }

    private void processNull(JCTree.JCClassDecl jcClassDecl) {
        for (JCTree tree : jcClassDecl.defs) {

            if (tree.getKind().equals(Tree.Kind.METHOD)) {
                if ("<init>".equals(((JCTree.JCMethodDecl) tree).name.toString())) {
                    continue;
                }
                JCTree.JCMethodDecl jcMethodDecl = (JCTree.JCMethodDecl) tree;

                final List<JCTree.JCVariableDecl> parameters = jcMethodDecl.getParameters();

                final String methodName = jcMethodDecl.getName().toString();
                // set方法只有一个参数
                if (parameters.length() != 1) {
                    continue;
                }
                // 参数是原始类型
                final JCTree.JCVariableDecl parameter = parameters.get(0);
                if (parameter.vartype.type.getKind().isPrimitive()) {
                    continue;
                }
                // set add方法
                if (!methodName.startsWith("set") && !methodName.startsWith("add")) {
                    continue;
                }
                messager.printMessage(Diagnostic.Kind.NOTE, methodName + " has been processed");

                // if (param == null) return;
                final JCTree.JCIf ifNullReturn = treeMaker.If(
                        treeMaker.Binary(
                                JCTree.Tag.EQ,
                                treeMaker.Ident(parameter),
                                treeMaker.Literal(TypeTag.BOT, null)
                        ),
                        treeMaker.Return(treeMaker.Ident(names.fromString("this"))),
                        null
                );

                jcMethodDecl.body = treeMaker.Block(0, List.of(
                        ifNullReturn,
                        jcMethodDecl.body
                ));
            }
        }
    }



}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值