首页 > 编程 > Java > 正文

更为方便的书写编译时注解——javapoet

2019-11-06 09:58:54
字体:
来源:转载
供稿:网友

简介

  编译时注解以其在保有注解低耦合等传统特点的同时又能兼顾性能被开发人员所热爱,但是,在写编译过程动态生成代码文件时的琐碎工作让人头疼,square公司推出的javapoet则完美的解决了这一问题,让动态生成代码不在难写。这里介绍下这个框架。

一、注解部分

  这里不在对注解部分做详细的描述,网上有很多关于java注解的资料,再此只对在做注解时运用到的两个注解和一个抽象类进行大概的介绍。

  写注解时用到的两个注解Retention和Target,其中Retention注解的属性值为RetentionPolicy类型,而RetentionPolicy为枚举类:

public enum RetentionPolicy {    /**     * Annotations are to be discarded by the compiler.     */    SOURCE,    /**     * Annotations are to be recorded in the class file by the compiler     * but need not be retained by the VM at run time.  This is the default     * behavior.     */    CLASS,    /**     * Annotations are to be recorded in the class file by the compiler and     * retained by the VM at run time, so they may be read reflectively.     *     * @see java.lang.reflect.AnnotatedElement     */    RUNTIME}  其中的三个枚举类型代表这注解的运行范围

  SOURCE:停留在代码中,不会参与编译;

  ClASS:会被记录在Class文件中,但不参与运行时调用;

  RUNTIME:运行时可用。

  Target注解的属性值是ElementType,作用是规定被注解对象的具体类型

public enum ElementType {    /** Class, interface (including annotation type), or enum declaration */    TYPE,    /** Field declaration (includes enum constants) */    FIELD,    /** Method declaration */    METHOD,    /** Formal parameter declaration */    PARAMETER,    /** Constructor declaration */    CONSTRUCTOR,    /** Local variable declaration */    LOCAL_VARIABLE,    /** Annotation type declaration */    ANNOTATION_TYPE,    /** Package declaration */    PACKAGE,    /**     * Type parameter declaration     *     * @since 1.8     */    TYPE_PARAMETER,    /**     * Use of a type     *     * @since 1.8     */    TYPE_USE}

  还有一个编译时所需要的抽象类AbstractPRocessor,想要了解的更多可以看下鸿洋大神的博客http://blog.csdn.net/lmj623565791/article/details/43452969

二、Javapoet部分

  进入重点,首先明白在一个.java文件的构造中,包含四大元素:成员变量(Field)、方法(method)、类或接口(Type)、文件(File)。在Javapoet中,对这四大元素有对应的操作类:

  FieldSpec: 负责控制成员变量及常量的声明  MethodSpec: 负责生成类中的方法  TypeSpec: 负责类或者接口的部分生成  JavaFile: 负责在根据制定的位置进行文件的输出,以及进行必要的类包导入

  先上一段经典的helloworld纪念逝去的青春:

FieldSpec fieldSpec = FieldSpec.builder(String.class,"world")                .addModifiers(Modifier.PRIVATE,Modifier.STATIC,Modifier.FINAL)                .initializer("$S","World")                .build();        MethodSpec methodSpec = MethodSpec.methodBuilder("main")                .addModifiers(Modifier.PUBLIC, Modifier.STATIC)                .returns(void.class)                .addParameter(String[].class, "args")                .addStatement("$T.out.println($S+$N+/"$L/")", System.class,"Hello",fieldSpec,"!")                .build();        TypeSpec typeSpec = TypeSpec.classBuilder("HelloWorld")                .addModifiers(Modifier.PUBLIC)                .addField(fieldSpec)                .addMethod(methodSpec)                .build();        JavaFile javaFile = JavaFile.builder("com.example",typeSpec)                .build();        javaFile.writeTo(System.out);       生成代码如下:

  可以注意到,除了JavaFile中,都对Modifier进行了使用,这个类的作用就是设置声明、方法、以及类的修饰语关键字,它本身是一个枚举类。

      addStatement方法可以直接写入代码行,需要注意的时不用加”;”

  再细致点可以发现,输出语句中使用了$S、$L、$N、$T四种占位符

      $T:表示需要调用类或者接口;

      $L:表示要对应的常量

      $S:表示对应的字符串(和$L的区别在于,字符串进入代码中仍为字符串,而$L则不会加"")

      $N:表示对应(FieldSpec、MethodSpec、TypeSpec)要注入的变量常量、方法、类的名字。

  需要注意的是,在Javapoet中会帮你自动引入包,如果想要手动引入自己需要的包,还可以通过JavaFile.Builder生成的对象调用addStaticImort( )方法。

    在JavaPoet中还有更多好用的方法,比如beginControlFlow和endControlFlow等,在github上可以直接看到,就不在一一例举了

 github地址:https://github.com/square/javapoet


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表