目录
1.什么是AbstractProcessor
AbstractProcessor是java提供的可以在编译期对自定义的注解进行拦截,根据需求生成对应的类文件。本次demo主要是给注解类自动生成对应的属性
2.自动生成属性jar包
2.1 注解声明
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface AddField {
String fieldName() default "";
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface AddConstructor {
}
2.2 注解拦截模块代码
import com.sun.source.tree.Tree;
import com.sun.tools.javac.code.Flags;
import com.sun.tools.javac.code.TypeTag;
import com.sun.tools.javac.model.JavacElements;
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.wangxb.annotation.AddField;
import com.wangxb.annotation.AddConstructor;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import com.sun.tools.javac.api.JavacTrees;
import javax.annotation.processing.*;
import javax.lang.model.element.*;
import com.sun.tools.javac.util.Names;
import javax.lang.model.util.Types;
import javax.tools.Diagnostic;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
public class AddPropertieProcess extends AbstractProcessor{
//创建新的源,类或辅助文件的文件管理器
Filer filer;
//元素进行操作的一些实用方法的实现
JavacElements elements;
//报告错误,警告和其他通知的信使
Messager messager;
//注解处理工具的处理器特定选项
Map<String,String> options;
//用于对类型进行操作的实用方法的实现
Types types;
private static Map<String, String> tis = new ConcurrentHashMap<>();
private JavacTrees javacTrees;
private TreeMaker treeMaker;
private Names names;
@Override
public void init(ProcessingEnvironment processingEnv) {
super.init(processingEnv);
filer = processingEnv.getFiler();
elements = (JavacElements) processingEnv.getElementUtils();
messager = processingEnv.getMessager();
options = processingEnv.getOptions();
types = processingEnv.getTypeUtils();
javacTrees = JavacTrees.instance(processingEnv);
Context context = ((JavacProcessingEnvironment) processingEnv).getContext();
treeMaker = TreeMaker.instance(context);
names = Names.instance(context);
}
@Override
public Set<String> getSupportedAnnotationTypes() {
Set<String> set = new HashSet<>();
set.add(AddField.class.getCanonicalName());
return set;
}
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
boolean bRet = false;
Set<? extends Element> set = roundEnv.getElementsAnnotatedWith(AddField.class);
messager.printMessage(Diagnostic.Kind.WARNING,"测试消息");
for(Element element : set){
bRet = addField(element);
bRet = addConstructor(element);
}
return bRet = false;
}
//添加属性及方法
boolean addField(Element element){
System.out.println("添加属性及方法");
boolean bRet = false;
ElementKind elementKind = element.getKind();
if (elementKind != ElementKind.CLASS){
return bRet;
}
AddField addField = element.getAnnotation(AddField.class);
String fieldName = addField.fieldName();
if (StringUtils.isBlank(fieldName)){
return bRet;
}
JCTree jcTree = elements.getTree(element);
jcTree.accept(new TreeTranslator() {
@Override
public void visitClassDef(JCTree.JCClassDecl jcClassDecl) {
treeMaker.pos = jcClassDecl.pos;//注意 偏移必须对准
JCTree.JCVariableDecl jcVariableDecl = treeMaker.VarDef(treeMaker.Modifiers(Flags.PUBLIC),names.fromString(fieldName),treeMaker.Ident(names.fromString("String")),treeMaker.Literal("abc"));
jcClassDecl.defs = jcClassDecl.defs.append(jcVariableDecl);
if (addField.methed() == true){
jcClassDecl = addGetMethed(jcClassDecl,jcVariableDecl);
jcClassDecl = addSetMethed(jcClassDecl,jcVariableDecl);
}
this.result = jcClassDecl;
super.visitClassDef(jcClassDecl);
}
});
return bRet = true;
}
//添加Get方法
JCTree.JCClassDecl addGetMethed(JCTree.JCClassDecl jcClassDecl,JCTree.JCVariableDecl jcVariableDecl){
JCTree.JCIdent jcIdent = treeMaker.Ident(names.fromString("this"));
JCTree.JCExpression jcExpression = treeMaker.Select(jcIdent, jcVariableDecl.getName());
JCTree.JCReturn jcReturn = treeMaker.Return(jcExpression);
ArrayList<JCTree.JCStatement> jcStatementList = new ArrayList<JCTree.JCStatement>();
jcStatementList.add(jcReturn);
JCTree.JCBlock jcBlock = treeMaker.Block(0, List.from(jcStatementList));
String methedName = "get" + jcVariableDecl.name.toString();
JCTree.JCMethodDecl jcMethodDecl = treeMaker.MethodDef(treeMaker.Modifiers(Flags.PUBLIC),names.fromString(methedName),jcVariableDecl.vartype, List.nil(),List.nil(),List.nil(),jcBlock,null);
jcClassDecl.defs = jcClassDecl.defs.append(jcMethodDecl);
return jcClassDecl;
}
//添加Set方法
JCTree.JCClassDecl addSetMethed(JCTree.JCClassDecl jcClassDecl,JCTree.JCVariableDecl jcVariableDecl){
ArrayList<JCTree.JCStatement> jcStatementList = new ArrayList<JCTree.JCStatement>();
String methedName = "set" + jcVariableDecl.name.toString();
JCTree.JCVariableDecl jcParamVariableDecl = treeMaker.VarDef(treeMaker.Modifiers(Flags.PARAMETER),jcVariableDecl.name,jcVariableDecl.vartype,null);
String memberAccess = "this." + jcVariableDecl.getName();
JCTree.JCExpression jcExpression = memberAccess(memberAccess);
JCTree.JCStatement jcStatement = memberAssign(jcExpression,jcParamVariableDecl);
jcStatementList.add(jcStatement);
JCTree.JCExpression jcParamType = memberAccess("java.lang.String");
ArrayList<JCTree.JCExpression> paramTypeList = new ArrayList();
paramTypeList.add(jcParamType);
paramTypeList.add(jcParamType);
JCTree.JCExpression printLiteral = varDef("%s");
JCTree.JCExpression paramValue = varDef(jcParamVariableDecl);
ArrayList<JCTree.JCExpression> paramValueList = new ArrayList();
paramValueList.add(printLiteral);
paramValueList.add(paramValue);
JCTree.JCStatement printFunction = methodExec("java.lang.System.out.printf",paramTypeList,paramValueList);
jcStatementList.add(printFunction);
JCTree.JCBlock jcBlock = treeMaker.Block(0, List.from(jcStatementList));
System.out.println("代码块:" + jcBlock.toString());
JCTree.JCMethodDecl jcMethodDecl = treeMaker.MethodDef(treeMaker.Modifiers(Flags.PUBLIC),names.fromString(methedName),treeMaker.TypeIdent(TypeTag.VOID), List.nil(),List.of(jcParamVariableDecl),List.nil(),jcBlock,null);
jcClassDecl.defs = jcClassDecl.defs.append(jcMethodDecl);
return jcClassDecl;
}
//变量定义
JCTree.JCExpression varDef(JCTree.JCVariableDecl jcVariableDecl){
JCTree.JCIdent paramValue = treeMaker.Ident(jcVariableDecl.getName());
return paramValue;
}
//变量定义
JCTree.JCExpression varDef(String value){
JCTree.JCLiteral jcLiteral = treeMaker.Literal("%s");
return jcLiteral;
}
//方法执行
JCTree.JCStatement methodExec(String methodName,ArrayList<JCTree.JCExpression> paramTypeList,ArrayList<JCTree.JCExpression> paramValueList){
JCTree.JCExpression jcMethodIdent = memberAccess(methodName);
JCTree.JCMethodInvocation jcMethodInvocation = treeMaker.Apply(List.from(paramTypeList),jcMethodIdent,List.from(paramValueList));
JCTree.JCExpressionStatement jcExpressionStatement = treeMaker.Exec(jcMethodInvocation);
return jcExpressionStatement;
}
//添加成员访问
JCTree.JCExpression memberAccess(String components) {
String[] componentArray = components.split("\\.");
JCTree.JCExpression expr = treeMaker.Ident(names.fromString(componentArray[0]));
for (int i = 1; i < componentArray.length; i++) {
expr = treeMaker.Select(expr, names.fromString(componentArray[i]));
}
return expr;
}
//添加赋值变量
JCTree.JCStatement memberAssign(JCTree.JCExpression jcExpression,JCTree.JCVariableDecl jcVariableDecl){
JCTree.JCAssign jcAssign = treeMaker.Assign(jcExpression,treeMaker.Ident(jcVariableDecl.getName()));
JCTree.JCStatement jcStatement = treeMaker.Exec(jcAssign);
return jcStatement;
}
//添加赋值常量
JCTree.JCStatement memberAssign(JCTree.JCExpression jcExpression,String value){
JCTree.JCAssign jcAssign = treeMaker.Assign(jcExpression,treeMaker.Literal(value));
JCTree.JCStatement jcStatement = treeMaker.Exec(jcAssign);
return jcStatement;
}
//创建构造函数
boolean addConstructor(Element element){
System.out.println("添加所有的属性设置");
boolean bRet = false;
ElementKind elementKind = element.getKind();
if (elementKind != ElementKind.CLASS){
return bRet;
}
AddConstructor addConstructor = element.getAnnotation(AddConstructor.class);
if (ObjectUtils.isEmpty(addConstructor)){
return bRet;
}
JCTree jcTree = elements.getTree(element);
jcTree.accept(new TreeTranslator() {
@Override
public void visitClassDef(JCTree.JCClassDecl jcClassDecl) {
ArrayList<JCTree.JCVariableDecl> paramList = getParam(jcClassDecl);
if (ObjectUtils.isEmpty(paramList)){
jcClassDecl = createNoArgsConstructor(jcClassDecl);
}else{
jcClassDecl = createAllArgsConstructor(jcClassDecl,paramList);
}
this.result = jcClassDecl;
super.visitClassDef(jcClassDecl);
}
});
return bRet = true;
}
//创建有参构造函数
JCTree.JCClassDecl createAllArgsConstructor(JCTree.JCClassDecl jcClassDecl,ArrayList<JCTree.JCVariableDecl> paramList) {
System.out.println("创建有参构造函数");
treeMaker.pos = jcClassDecl.pos;
ArrayList<JCTree.JCStatement> jcStatementList = new ArrayList<>();
ArrayList<JCTree.JCVariableDecl> newParamList = new ArrayList<>();
for(JCTree.JCVariableDecl jcVariableDecl : paramList) {
JCTree.JCVariableDecl jcParamVariableDecl = treeMaker.VarDef(treeMaker.Modifiers(Flags.PARAMETER),jcVariableDecl.name,jcVariableDecl.vartype,null);
JCTree.JCIdent jcIdent = treeMaker.Ident(names.fromString("this"));
JCTree.JCExpression jcExpression = treeMaker.Select(jcIdent, jcVariableDecl.getName());
JCTree.JCAssign jcAssign = treeMaker.Assign(jcExpression,treeMaker.Ident(jcParamVariableDecl.getName()));
JCTree.JCStatement jcStatement = treeMaker.Exec(jcAssign);
newParamList.add(jcParamVariableDecl);
jcStatementList.add(jcStatement);
}
JCTree.JCBlock block = treeMaker.Block(0, List.from(jcStatementList));
JCTree.JCMethodDecl jcMethodDecl = treeMaker.MethodDef(treeMaker.Modifiers(Flags.PUBLIC),names.fromString("<init>"),
treeMaker.TypeIdent(TypeTag.VOID), List.nil(),List.from(newParamList), List.nil(),block,null);
jcClassDecl.defs = jcClassDecl.defs.append(jcMethodDecl);
return jcClassDecl;
}
//创建无参构造函数
JCTree.JCClassDecl createNoArgsConstructor(JCTree.JCClassDecl jcClassDecl) {
System.out.println("创建无参构造函数");
if (hasNoArgsConstructor(jcClassDecl) == true){
return jcClassDecl;
}
treeMaker.pos = jcClassDecl.pos;//注意 偏移必须对准
JCTree.JCBlock block = treeMaker.Block(0, List.nil());//空代码块
JCTree.JCMethodDecl jcMethodDecl = treeMaker.MethodDef(treeMaker.Modifiers(Flags.PUBLIC),//访问标识
names.fromString("<init>"),//方法名
treeMaker.TypeIdent(TypeTag.VOID),//返回值类型
List.nil(),//泛型列表
List.nil(),//参数列表
List.nil(),//抛出的异常
block,//代码块
null);
jcClassDecl.defs = jcClassDecl.defs.append(jcMethodDecl);
return jcClassDecl;
}
//判断是否已经有默认的空参构造器
private boolean hasNoArgsConstructor(JCTree.JCClassDecl jcClassDecl) {
for (JCTree jcTree:jcClassDecl.defs){
if(jcTree.getKind().equals(Tree.Kind.METHOD)){
JCTree.JCMethodDecl methodDecl= (JCTree.JCMethodDecl) jcTree;
if(methodDecl.getName().toString().equals("<init>")&&methodDecl.getParameters().isEmpty()){
return true;
}
}
}
return false;
}
//获取所有非静态Final变量
private ArrayList<JCTree.JCVariableDecl> getParam(JCTree.JCClassDecl jcClassDecl) {
ArrayList<JCTree.JCVariableDecl> paramList = new ArrayList<>();
for (JCTree tree:jcClassDecl.defs){
if(tree.getKind().equals(Tree.Kind.VARIABLE)){
JCTree.JCVariableDecl variableDecl= (JCTree.JCVariableDecl) tree;
Set<Modifier> flags = variableDecl.mods.getFlags();
if(!flags.contains(Modifier.FINAL)&&!flags.contains(Modifier.STATIC)){
paramList.add(variableDecl);
}
}
}
return paramList;
}
}
2.3 注解拦截模块资源文件
在resource目录下添加META/services/javax.annotation.processing.Processor文件
文件内容为AddPropertieProcess的引用包名
2.4 注解拦截模块POM文件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>TestDemo</artifactId>
<groupId>com.wangxb</groupId>
<version>1.0.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<packaging>jar</packaging>
<artifactId>TestProcess</artifactId>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>com.squareup</groupId>
<artifactId>javapoet</artifactId>
<version>1.13.0</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.12.0</version>
</dependency>
<dependency>
<groupId>com.sun</groupId>
<artifactId>tools</artifactId>
<version>1.8.0</version>
<scope>system</scope>
<systemPath>${env.JAVA_HOME}/lib/tools.jar</systemPath>
<optional>true</optional>
</dependency>
</dependencies>
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<excludes>
<exclude>META-INF/**/*</exclude>
</excludes>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<mainClass>none</mainClass> <!-- 取消查找本项目下的Main方法:为了解决Unable to find main class的问题 -->
<classifier>execute</classifier> <!-- 为了解决依赖模块找不到此模块中的类或属性 -->
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<!--
指定Java compiler编译时,使用的source与target版本。
注: 不同的source、target版本,编译后产生的Class版本号可能不同
-->
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>3.1.0</version>
<executions>
<execution>
<id>process-META</id>
<phase>prepare-package</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>target/classes</outputDirectory>
<resources>
<resource>
<directory>${basedir}/src/main/resources/</directory>
<includes>
<include>**/*</include>
</includes>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
2. 测试DEMO
创建测试DEMO,引入生成的注解拦截jar包
@Service
@AddConstructor
@AddField(fieldName = "d")
public class AService {
public String k;
public long l;
}
编译后将自动生成abc的属性
3.调试程序
在测试模块目录执行 mvnDebug clean install,调试端口号为8000
在注解拦截模块选择
选择对应的端口,调试即可