lombok实现原理

大家在做java程序开发时会用到Lombok插件,在使用时大家都觉得其很方面,帮助我们消除Java代码的冗长,那么它的实现原理是什么呢?

在javac解析称抽象语法树之后,Lombok通过自己的注解解释器,动态修改语法树,插入新的节点到语法树中,最后通过分析生成字节码。

例如创建一个名为Getter的注解。

 1 package annotation;
 2 
 3 import java.lang.annotation.ElementType;
 4 import java.lang.annotation.Retention;
 5 import java.lang.annotation.RetentionPolicy;
 6 import java.lang.annotation.Target;
 7 
 8 @Target(ElementType.TYPE)
 9 @Retention(RetentionPolicy.CLASS)
10 public @interface Getter {
11 }

为这个注解添加一个GetterProcessor解释器。JCTree、TreeMaker的相关用法见https://www.cnblogs.com/lwjblogs/p/15741065.html

 1 import annotation.Getter;
 2 import com.sun.source.tree.Tree;
 3 import com.sun.tools.javac.api.JavacTrees;
 4 import com.sun.tools.javac.code.Flags;
 5 import com.sun.tools.javac.processing.JavacProcessingEnvironment;
 6 import com.sun.tools.javac.tree.JCTree;
 7 import com.sun.tools.javac.tree.TreeMaker;
 8 import com.sun.tools.javac.tree.TreeTranslator;
 9 import com.sun.tools.javac.util.*;
10 
11 import javax.annotation.processing.*;
12 import javax.lang.model.SourceVersion;
13 import javax.lang.model.element.Element;
14 import javax.lang.model.element.TypeElement;
15 import javax.tools.Diagnostic;
16 import java.util.Set;
17 
18 @SupportedSourceVersion(SourceVersion.RELEASE_8)
19 @SupportedAnnotationTypes("annotation.Getter")
20 public class GetterProcessor extends AbstractProcessor {
21 
22     private Messager messager;
23 
24     private TreeMaker treeMaker;
25 
26     private JavacTrees trees;
27 
28     private Names names;
29     @Override
30     public synchronized void init(ProcessingEnvironment processingEnv) {
31         super.init(processingEnv);
32         this.messager = processingEnv.getMessager();
33         this.trees = JavacTrees.instance(processingEnv);
34         Context context =((JavacProcessingEnvironment) processingEnv).getContext();
35         this.names = Names.instance(context);
36         this.treeMaker = TreeMaker.instance(context);
37     }
38 
39     @Override
40     public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
41         Set<? extends Element> set = roundEnv.getElementsAnnotatedWith(Getter.class);
42         set.forEach(element->{
43             JCTree jcTree = trees.getTree(element);
44             jcTree.accept(new TreeTranslator(){
45                 @Override
46                 public void visitClassDef(JCTree.JCClassDecl jcClassDecl) {
47                     List<JCTree.JCVariableDecl> jcVariableDecls = List.nil();
48                     for(JCTree jcTree : jcClassDecl.defs){
49                         if(jcTree.getKind().equals(Tree.Kind.VARIABLE)){
50                             JCTree.JCVariableDecl jcVariableDecl = (JCTree.JCVariableDecl) jcTree;
51                             jcVariableDecls = jcVariableDecls.append(jcVariableDecl);
52                         }
53                     }
54                     jcVariableDecls.forEach(jcVariableDecl -> {
55                         messager.printMessage(Diagnostic.Kind.NOTE, jcVariableDecl.getName() + " has been processed");
56                         jcClassDecl.defs = jcClassDecl.defs.prepend(makeGetterDecl(jcVariableDecl));
57                     });
58                     super.visitClassDef(jcClassDecl);
59                 }
60             });
61         });
62         return true;
63     }
64 
65     private JCTree makeGetterDecl(JCTree.JCVariableDecl jcVariableDecl){
66         ListBuffer<JCTree.JCStatement> listBuffer = new ListBuffer<>();
67         listBuffer.add(treeMaker.Return(treeMaker.Select(treeMaker.Ident(names.fromString("this")),jcVariableDecl.getName())));
68         JCTree.JCBlock block = treeMaker.Block(0,listBuffer.toList());
69         return treeMaker.MethodDef(treeMaker.Modifiers(Flags.PUBLIC),getNewMethodName(jcVariableDecl.getName())
70                 ,jcVariableDecl.vartype, List.nil(), List.nil(), List.nil(),block,null);
71     }
72 
73     private Name getNewMethodName(Name name) {
74         String s = name.toString();
75         return names.fromString("get" + s.substring(0, 1).toUpperCase() + s.substring(1, name.length()));
76     }
77 }

创建一个名为Demo的测试样例。

import annotation.Getter;

@Getter
public class Demo{
    private String test;

    private String value;
}

使用javac编译Getter.java和GetterProcess.java成为Getter.class和GetterProcess.class

使用javac编译Demo.java javac -processor processor.GetterProcessor Demo.java 编译成功以后会生成一个Demo.class文件。

import annotation.Getter;

@Getter
public class Demo {
    private String test;
    private String value;

    public String getValue() {
        return this.value;
    }

    public String getTest() {
        return this.test;
    }

    public Demo() {
    }
}

可以看见在Demo.class文件中,已经成功生成了test和value的get方法。

setter方法也可以通过此方式实现。

 

posted @ 2021-12-28 14:54  jkbolck  阅读(654)  评论(0)    收藏  举报