Lombok
Lombok注解
val 局部变量为final@NonNull 对方法参数空检验,如果为空,抛出NullPointerException@CleanUp 局部变量在执行完毕之后try-catch自动清除@Getter @Setter @ToString @EqualsAndHashCode @NoArgsConstructor @RequiredArgsConstructor @AllArgsConstructor @Data @Value 为类的属性变为final, 只提供getter方法@Builder @SneakyThrows 自动跑出异常@Getter(lazy=true) @Log (自动在类中注入日志对象)
@CommonsLog @Log @Log4j @Log4j2 @Slf4j XSlf4j
Lombok执行流程
- java源码
- 解析转化java文件
- AST抽象语法树解析
- Annotation Processing
- Lombok注解处理
- AST
- Lombok注解Handler
- AST语法树修改完成
- 分析并生成class文件
Lombok使用
@Getter
class Lombok{
public String name = "lombok";
public static void main(String[] args) {
Lombok lombok = new Lombok();
System.out.println(lombok.getName());
}
}
class Lombok {
public String name = "lombok";
Lombok() {
}
public static void main(String[] args) {
Lombok lombok = new Lombok();
System.out.println(lombok.getName());
}
public String getName() {
return this.name;
}
}
手写Lombok Setter
package test;
import com.sun.source.tree.Tree;
import com.sun.tools.javac.code.Type;
import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.tree.TreeTranslator;
import javax.annotation.processing.*;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.TypeElement;
import com.sun.tools.javac.util.Context;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.Set;
import com.sun.tools.javac.tree.TreeMaker;
import com.sun.tools.javac.api.JavacTrees;
import com.sun.tools.javac.util.*;
import com.sun.tools.javac.processing.JavacProcessingEnvironment;
import javax.lang.model.element.Element;
import javax.tools.Diagnostic;
import com.sun.tools.javac.code.Flags;
@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.TYPE)
@interface MySetter {
}
@SupportedSourceVersion(SourceVersion.RELEASE_8)
@SupportedAnnotationTypes("test.MySetter")
public class MySetterProcessor extends AbstractProcessor{
private Messager messager;
private JavacTrees javacTrees;
private TreeMaker treeMaker;
private Names names;
@Override
public synchronized void init(ProcessingEnvironment processingEnv) {
super.init(processingEnv);
this.messager = processingEnv.getMessager();
this.javacTrees = 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> elementsAnnotatedWith = roundEnv.getElementsAnnotatedWith(MySetter.class);
elementsAnnotatedWith.forEach(e -> {
JCTree tree = javacTrees.getTree(e);
tree.accept(new TreeTranslator() {
@Override
public void visitClassDef(JCTree.JCClassDecl jcClassDecl) {
List<JCTree.JCVariableDecl> jcVariableDeclList = List.nil();
for (JCTree jcTree : jcClassDecl.defs) {
if (jcTree.getKind().equals(Tree.Kind.VARIABLE)) {
JCTree.JCVariableDecl jcVariableDecl = (JCTree.JCVariableDecl) jcTree;
jcVariableDeclList = jcVariableDeclList.append(jcVariableDecl);
}
}
jcVariableDeclList.forEach(jcVariableDecl -> {
messager.printMessage(Diagnostic.Kind.NOTE, jcVariableDecl.getName() + " has been processed");
jcClassDecl.defs = jcClassDecl.defs.prepend(makeSetterMethodDecl(jcVariableDecl));
});
super.visitClassDef(jcClassDecl);
}
});
});
return true;
}
private JCTree.JCMethodDecl makeSetterMethodDecl(JCTree.JCVariableDecl jcVariableDecl) {
ListBuffer<JCTree.JCStatement> statements = new ListBuffer<>();
JCTree.JCExpressionStatement aThis = makeAssignment(treeMaker.Select(treeMaker.Ident(
names.fromString("this")), jcVariableDecl.getName()), treeMaker.Ident(jcVariableDecl.getName()));
statements.append(aThis);
JCTree.JCBlock block = treeMaker.Block(0, statements.toList());
JCTree.JCVariableDecl param = treeMaker.VarDef(treeMaker.Modifiers(Flags.PARAMETER),
jcVariableDecl.getName(), jcVariableDecl.vartype, null);
List<JCTree.JCVariableDecl> parameters = List.of(param);
JCTree.JCExpression methodType = treeMaker.Type(new Type.JCVoidType());
return treeMaker.MethodDef(treeMaker.Modifiers(Flags.PUBLIC),
getNewMethodName(jcVariableDecl.getName()), methodType, List.nil(),
parameters, List.nil(), block, null);
}
private Name getNewMethodName(Name name) {
String s = name.toString();
return names.fromString("set" + s.substring(0, 1).toUpperCase() + s.substring(1, name.length()));
}
private JCTree.JCExpressionStatement makeAssignment(JCTree.JCExpression lhs, JCTree.JCExpression rhs) {
return treeMaker.Exec(
treeMaker.Assign(
lhs,
rhs
)
);
}
}
1. 编译自定义注解器和自定义注解处理器(必须使用tools.jar)
javac -cp $JAVA_HOME/lib/tools.jar MySetter* -d .
2. 使用自定义注解处理器来编译文件
javac -processor test.MySetterProcessor LomTest.java
3. 通过idea查看编译之后并反编译的class文件
package test;
@MySetter
public class LombokTest {
public String name;
}
package test;
public class LombokTest {
public String name;
public void setName(String var1) {
this.name = var1;
}
public LombokTest() {
}
}
关于插件
- lombok在idea编译需要lombok插件的支持,要不会报错
@MySetter
public class LombokTest {
public String name;
public static void main(String[] args) {
LombokTest l = new LombokTest();
l.setName("lombok");
}
}
|