Skip to content

Instantly share code, notes, and snippets.

@huscael
Last active August 18, 2020 15:51
Show Gist options
  • Save huscael/7505f05c863108afabd37e13f33c17be to your computer and use it in GitHub Desktop.
Save huscael/7505f05c863108afabd37e13f33c17be to your computer and use it in GitHub Desktop.
[Java Annotation Processor Demo] java annotation processor #java #annotation
import com.google.auto.service.AutoService;
import com.sun.tools.javac.api.JavacTrees;
import com.sun.tools.javac.code.Flags;
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.ListBuffer;
import com.sun.tools.javac.util.Names;
import javax.annotation.processing.*;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.*;
import javax.tools.Diagnostic;
import java.util.ArrayList;
import java.util.Set;
@SupportedAnnotationTypes("com.huscarl.test.Helper")
@SupportedSourceVersion(SourceVersion.RELEASE_8)
@AutoService(Processor.class)
public class HelperProcessor extends AbstractProcessor {
/** 消息记录器 */
private Messager messager;
/** 可将Element转换为JCTree的工具 */
private JavacTrees trees;
/** JCTree制作器 */
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> elements = roundEnv.getElementsAnnotatedWith(Helper.class);
for (Element element: elements) {
java.util.List<JCTree.JCVariableDecl> fields = new ArrayList<>();
JCTree tree = trees.getTree(element);
tree.accept(new TreeTranslator() {
@Override
public void visitClassDef(JCTree.JCClassDecl tree) {
super.visitClassDef(tree);
tree.defs = tree.defs.append(generateMethod(fields));
}
@Override
public void visitVarDef(JCTree.JCVariableDecl tree) {
fields.add(tree);
super.visitVarDef(tree);
}
});
}
return false;
}
/**
* Description: generate toString method.
* @param fields class fields
* @return methodDef made by treeMaker
*/
public JCTree.JCMethodDecl generateMethod(java.util.List<JCTree.JCVariableDecl> fields) {
JCTree.JCBlock body = generateMethodBody(fields);
return treeMaker.MethodDef(
treeMaker.Modifiers(Flags.PUBLIC),
names.fromString("toString"),
treeMaker.Ident(names.fromString("String")),
List.nil(),
List.nil(),
List.nil(),
body,
null
);
}
public JCTree.JCBlock generateMethodBody(java.util.List<JCTree.JCVariableDecl> fields) {
try {
JCTree.JCBlock body = treeMaker.Block(Flags.BLOCK, List.nil());
java.util.List<String> formattedStrs = new ArrayList<>();
for (JCTree.JCVariableDecl field: fields) {
if (field.getModifiers().getFlags().contains(Modifier.PRIVATE)) {
formattedStrs.add(String.format( "%s:%%s", field.getName().toString()) );
}
}
ListBuffer<JCTree.JCExpression> args = new ListBuffer<>();
args.add(treeMaker.Literal(String.join(",", formattedStrs)));
fields.forEach(field -> {
if (field.getModifiers().getFlags().contains(Modifier.PRIVATE)) {
args.add(treeMaker.Apply(
List.nil(),
treeMaker.Select(
treeMaker.Ident(names.fromString("String")),
names.fromString("valueOf")
),
List.of(treeMaker.Ident(field.getName()))
));
}
});
JCTree.JCMethodInvocation invoke = treeMaker.Apply(
List.nil(),
treeMaker.Select(
treeMaker.Ident(names.fromString("String")),
names.fromString("format")
),
args.toList()
);
body.stats = body.getStatements().append(treeMaker.Return(invoke));
return body;
} catch (Exception e) {
e.printStackTrace();
messager.printMessage(Diagnostic.Kind.ERROR, e.getLocalizedMessage());
}
return null;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment