编译时注解:AbstractProcessor javapoe自动生成代码

前沿:AbstractProcessor介绍
AbstractProcessor,是一个抽象类,该类实现了接口Processor。
抽象类AbstractProcessor以及接口Processor都是位于包javax.annotation.processing中。该接口中定义的所有类、接口都是与实现注解处理器相关的。
现行比较流行的是注解式框架,AOP解耦:获取控件,检查权限,检查登陆状态等等许多操作,类似于市面上的ButterKnife,Retrofit,Dragger,EventBus等等都选择使用注解来配置。注解又分为两种类型,一种是运行时注解,另一种是编译时注解。运行时注解因为性能原因一般不会在项目中过多的使用。比较有代表的注解控件框架xutils和ButterKnife,xutils使用的是运行时注解,ButterKnife使用的编译时注解。

RetentionPolicy源码见:sdk文档

  1. RetentionPolicy.SOURCE:注解只保留在源文件,当Java文件编译成class文件的时候,注解被遗弃,是3种生命周期中最短的注解;
  2. 编译时注解(RetentionPolicy.CLASS),作用域class字节码上,生命周期只有在编译器间有效。
  3. RetentionPolicy.RUNTIME:注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在
package java.lang.annotation;

public enum RetentionPolicy {
    SOURCE,  //在原文件中有效,被编译器丢弃。 
    CLASS,     //在class文件有效,可能会被虚拟机忽略。
    RUNTIME; //在运行时有效。

    private RetentionPolicy() {
    }
}

在这里插入图片描述
本章内容不主要介绍编译时注解,这个仿照ButterKnife挺详细 :编译时注解
本章主要介绍,在编译时注解时怎么用代码写代码,没错你没看错。
在这里用到了开源项目: javapoet
javapoet用法:
常用类:

  1. MethodSpec 代表一个构造函数或方法声明。
  2. TypeSpec 代表一个类,接口,或者枚举声明。
  3. FieldSpec代表一个成员变量,一个字段声明。
  4. JavaFile包含一个顶级类的Java文件。
    占位符:
  5. $S for Strings
  6. $T for Types
  7. $N for Names(我们自己生成的方法名或者变量名等等)

生成文件:

第一种生成方法:
private void generateHelloworld() throws IOException{
        //main代表方法名
        MethodSpec main = MethodSpec.methodBuilder("main") 
                 .addModifiers(Modifier.PUBLIC,Modifier.STATIC)//Modifier 修饰的关键字
                .addParameter(String[].class, "args") //添加string[]类型的名为args的参数
                //其实就是添加了System,out.println("Hello World");
                .addStatement("$T.out.println($S)", System.class,"Hello World") 
                .build();
        //HelloWorld是类名
       TypeSpec typeSpec = TypeSpec.classBuilder("HelloWorld")
                .addModifiers(Modifier.FINAL,Modifier.PUBLIC)
                .addMethod(main)  //在类中添加方法
                .build();
       JavaFile javaFile = JavaFile.builder("com.example.helloworld", typeSpec)
                .build();
        javaFile.writeTo(System.out);
    }
    

 1. for循环:

    MethodSpec main = MethodSpec.methodBuilder("main")
    .addCode(""
        + "int total = 0;\n"
        + "for (int i = 0; i < 10; i++) {\n"
        + "  total += i;\n"
        + "}\n")
    .build();
  
 2. for循环第二种方式:
 
    MethodSpec main = MethodSpec.methodBuilder("main")
    .addStatement("int total = 0")
    .beginControlFlow("for (int i = 0; i < 10; i++)")
    .addStatement("total += i")
    .endControlFlow()
    .build();

computeRange方法

private MethodSpec computeRange(String name, int from, int to, String op) {
  return MethodSpec.methodBuilder(name)
      .returns(int.class)
      .addStatement("int result = 0")
      .beginControlFlow("for (int i = " + from + "; i < " + to + "; i++)")
      .addStatement("result = result " + op + " i")
      .endControlFlow()
      .addStatement("return result")
      .build();
 }
TypeSpec typeSpec = TypeSpec.classBuilder("HelloWorld")
            .addModifiers(Modifier.FINAL,Modifier.PUBLIC)
            .addMethod(computeRange("multiply10to20", 10, 20, "*"))
            .build();
JavaFile javaFile = JavaFile.builder("com.example.helloworld", typeSpec)
            .build();
javaFile.writeTo(System.out);
    
生成代码:
package com.example.helloworld;

public final class HelloWorld {
  int multiply10to20() {
    int result = 0;
    for (int i = 10; i < 20; i++) {
      result = result * i;
    }
    return result;
  }
}

添加import导入路径 addStaticImport:

JavaFile.builder("com.example.helloworld", hello)
    .addStaticImport(hoverboard, "createNimbus")
    .addStaticImport(namedBoards, "*")
    .addStaticImport(Collections.class, "*")
    .build();
就会导入这些文件
import static com.mattel.Hoverboard.Boards.*;
import static com.mattel.Hoverboard.createNimbus;
import static java.util.Collections.*;

类中添加变量 FieldSpec:

FieldSpec android = FieldSpec.builder(String.class, "android")
    .addModifiers(Modifier.PRIVATE, Modifier.FINAL)
    .initializer("$S + $L", "Lollipop v.", 5.0d)
    .build();
TypeSpec helloWorld = TypeSpec.classBuilder("HelloWorld")
    .addModifiers(Modifier.PUBLIC)
    .addField(android)
    .addField(String.class, "robot", Modifier.PRIVATE, Modifier.FINAL)
    .build();
效果:
   public class HelloWorld {
 	 	private final String android = "Lollipop v." + 5.0;
  		private final String robot;
	} 
  1. MethodSpec .addJavadoc(“XXX”) 方法上面添加注释
  2. MethodSpec.constructorBuilder() 构造器
  3. MethodSpec.addAnnotation(Override.class); 方法上面添加注解
  4. TypeSpec.enumBuilder(“XXX”) 生成一个XXX的枚举
  5. TypeSpec.interfaceBuilder(“HelloWorld”)生成一个HelloWorld接口 ==!
    例如编译时注解:
Filer mFiler = processingEnv.getFiler();
 //创建bindView方法
        MethodSpec.Builder bindViewMethod = MethodSpec.methodBuilder("bindView")
                .addModifiers(Modifier.PUBLIC)
                .addAnnotation(Override.class)
                .addParameter(TypeName.get(mTypeElement.asType()), "host")
                .addParameter(TypeName.OBJECT, "source")
                .addParameter(TypeUtil.PROVIDER, "finder");

        //bindView中添加查找控件对象方法
        for (BindViewField field : mFields) {
            bindViewMethod.addStatement("int id=host.getResources().getIdentifier($S, \"id\",host.getPackageName())", field.getFieldName());
            //根据属性名获取id
            bindViewMethod.addStatement("host.$N = ($T)(finder.findView(source, id))", field.getFieldName(), ClassName.get(field.getFieldType()));
        }

        //创建unBindView方法
        MethodSpec.Builder unBindViewMethod = MethodSpec.methodBuilder("unBindView")
                .addModifiers(Modifier.PUBLIC)
                .addParameter(TypeName.get(mTypeElement.asType()), "host")
                .addAnnotation(Override.class);
        //方法中的实现
        for (BindViewField field : mFields) {
            unBindViewMethod.addStatement("host.$N = null", field.getFieldName());
        }

        //创建类
        TypeSpec injectClass = TypeSpec.classBuilder(mTypeElement.getSimpleName() + "$$ViewBinder")
                .addModifiers(Modifier.PUBLIC)
                .addSuperinterface(ParameterizedTypeName.get(TypeUtil.BINDER, 			     TypeName.get(mTypeElement.asType())))
                .addMethod(bindViewMethod.build())
                .addMethod(unBindViewMethod.build())
                .build();
        String packageName = mElements.getPackageOf(mTypeElement).getQualifiedName().toString();

        JavaFile.builder(packageName, injectClass).build().writeTo(mFiler);

感谢各位大神文章帮助:参考文章

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值