自定义注解生成代码(一) —— javaPoetAPI详解
目录
最近发现一个有趣的库,javapoet翻译后就是java诗人,总而言之就是可以辅助我们在代码编译期间生成java代码,内部有良好的java格式并且可以完成自动导包,嗯真香。
类名 | 说明 |
---|---|
JavaFile | 用于构造输出包含一个顶级类的Java文件(控制生成的Java文件的输出的类) |
TypeSpec | 生成类,接口,或者枚举 |
MethodSpec | 生成构造函数或方法 |
FieldSpec | 生成成员变量或字段 |
ParameterSpec | 用来创建参数 |
AnnotationSpec | 用来创建注解 |
ClassName | 通过包名和类名生成的对象,在JavaPoet中相当于为其指定Class |
ParameterizedTypeName | 通过MainClass和IncludeClass生成包含泛型的Class |
addModifiers(Modifier... modifiers)
Modifier 是一个枚举对象,枚举值为修饰关键字 Public、Protected、Private、Static、Final 等等。
所有在JavaPoet
创建的对象都必须设置修饰符(包括方法、类、接口、枚举、参数、变量)。
addAnnotation(AnnotationSpec annotationSpec)
addAnnotation(ClassName annotation)
addAnnotation(Class<?> annotation)
该方法即为类或方法或参数设置注解,参数即可以是 AnnotationSpec
,也可以是ClassName
,还可以直接传递 Class
对象。
一般情况下,包含复杂属性的注解一般用 AnnotationSpec
,如果单纯添加基本注解,无其他附加属性可以直接使用 ClassName
或者 Class
即可。
addJavadoc(CodeBlock block)
addJavadoc(String format, Object... args)
在编写类、方法、成员变量时,可以通过addJavadoc来设置注释,可以直接传入String
对象,或者传入CodeBlock
(代码块)。
在 JavaPoet
中生成类、接口、枚举,必须得通过 TypeSpec
生成,而 classBuilder、interfaceBuilder、enumBuilder
便是创建其关键的方法:
TypeSpec.classBuilder("类名“)
TypeSpec.classBuilder(ClassName className)
TypeSpec.interfaceBuilder("接口名称")
TypeSpec.interfaceBuilder(ClassName className)
TypeSpec.enumBuilder("枚举名称")
TypeSpec.enumBuilder(ClassName className)
.superclass(ClassName className)
.addSuperinterface(ClassName className)
当继承父类存在泛型时,需要使用ParameterizedTypeName
ParameterizedTypeName get(ClassName rawType, TypeName... typeArguments)
返回的ParameterizedTypeName
对象,已经被添加泛型信息
addMethod(MethodSpec methodSpec)
通过配置MethodSpec
对象,使用addMethod
方法将其添加进TypeSpec
中。
addEnumConstan(String enumValue)
通过addEnumConstan
方法添加枚举值,参数为枚举值名称。
JavaPoet
生成成员变量
JavaPoet
生成成员变量是通过FieldSpec
的 build
方法生成.
builder(TypeName type, String name, Modifier... modifiers)
只要传入TypeName(Class)、name(名称)、Modifier(修饰符)
,就可以生成一个基本的成员变量。
成员变量一般来说由注解(Annotation)
、修饰符(Modifier)
、Javadoc
(注释)、initializer
(实例化)。
addAnnotation(TypeName name)
addModifiers(Modifier ...modifier)
addJavadoc(String format, Object... args)
由于上述三个方法,都在通用方法介绍过这里就不再重复介绍。
initializer(String format, Object... args)
即成员变量的实例化,例:
public Activity mActivity = new Activity;
而 initializer
方法中的内容就是"="
后面的内容,下面看下具体的代码实现,上面的成员变量:
ClassName activity = ClassName.get("android.app", "Activity");
FieldSpec spec = FieldSpec.builder(activity, "mActivity")
.addModifiers(Modifier.PUBLIC)
.initializer("new $T", activity)
.build();
JavaPoet生成方法分为两种,第一种是构造方法,另一种为常规的方法。
MethodSpec.constructorBuilder()
MethodSpec.methodBuilder(String name)
方法的主要构成有方法参数、注解、返回值、方法体、抛出异常五种,注解可以参考通用方法addAnnotation
,其他方法我们将会一一介绍:
addParameter(ParameterSpec parameterSpec)
设置方法参数的方法通过addParameterSpec来实现,ParameterSpec的具体使用参考下一小节。
returns(TypeName returnType)
设置方法的返回值,只需传入一个TypeName
对象,而TypeName
是ClassName,ParameterizedTypeName
的基类。
在JavaPoet中,设置方法体内容有两个方法,分别是addCode
和addStatement
:
addCode()
addStatement()
这两个本质上都是设置方法体内容,但是不同的是使用addStatement()
方法时,你只需要专注于该段代码的内容,至于结尾的分号和换行它都会帮你做好。
而addCode()
添加的方法体内容就是一段无格式的代码片,需要开发者自己添加其格式。
在JavaPoet中,设置方法体使用模板是比较常见的,因为addCode
和addStatement
方法都存在这样的一个重载:
addCode(String format, Object... args)
addStatement(String format, Object... args)
在JavaPoet中,format中存在三种特定的占位符:
$T
在JavaPoet代指的是TypeName,该模板主要将Class抽象出来,用传入的TypeName指向的Class来代替。
ClassName bundle = ClassName.get("android.os", "Bundle");
addStatement("$T bundle = new $T()",bundle)
上述添加的代码内容为:
Bundle bundle = new Bundle();
$N
在JavaPoet中代指的是一个名称,例如调用的方法名称,变量名称,这一类存在意思的名称
addStatement("data.$N()",toString)
上述代码添加的内容:
data.toString();
$S
在JavaPoet中就和 String.format
中 %s
一样,字符串的模板,将指定的字符串替换到$S的地方
.addStatement("super.$S(savedInstanceState)","onCreate")
即将"onCreate"字符串代替到$S的位置上.
.addException(TypeName name)
设置方法抛出异常,可以使用 addException
方法,传入指定的异常的 ClassName
,即可为该方法设置其抛出该异常.
JavaPoet生成方法参数
JavaPoet生成有参方法时,需要填充参数,而生成参数则需要通过 ParameterSpec
这个类。
addParameter(ParameterSpec parameterSpec)
初始化ParameterSpec
ParameterSpec.builder(TypeName type, String name, Modifier... modifiers)
给参数设置其Class
,以及参数名称,和修饰符.
通常来说参数的构成包括:参数的类型(Class)
、参数的名称(name)
、修饰符(modifiers)
、注解 (Annotation)
除了builder方法初始化类型、以及名称、修饰符之外,其余可以通过如下方法进行设置:
.addModifiers(Modifier modifier)
常用的修饰符有 PUBLIC, PROTECTED, PRIVATE, ABSTRACT, DEFAULT, STATIC, FINAL, TRANSIENT, VOLATILE, SYNCHRONIZED, NATIVE, STRICTFP;
addAnnotation(TypeName name)
添加修饰符、注解具体使用可参考通用方法。
JavaPoet生成注解
在JavaPoet创建类、成员变量、方法参数、方法,都会用到注解。
如果使用不包含属性的注解可以直接通过
.addAnnotation(TypeName name)
直接传入 TypeName
或者 Class
进行设置。
如果使用的注解包含属性,并且不止一个时,这时候就需要生成 AnnotationSpec
来解决,下面简单了解下AnnotationSpec
。
初始化 AnnotationSpec
AnnotationSpec.builder(ClassName type)
可以发现初始化,只需传入 ClassName
或者 Class
即可。
addMember(String name, String format, Object... args)
使用 addMember
可以设置注解的属性值,name
对应的就是属性名称,format
的内容即属性体,同样方法体的格式化在这里也是适用的。
如果上述内容你已经看完,那么恭喜你,你已经明白JavaPoet的意图,但是现在的你,还差最后一步,即如何生成代码。
JavaPoet中负责生成的类是JavaFile
JavaFile.builder(String packageName, TypeSpec typeSpec)
JavaFile
通过向 build
方法传入 PackageName(Java文件的包名)、TypeSpec(生成的内容)
生成。
javaFile.writeTo(System.out)
生成的内容会输出到控制台中
javaFile.writeTo(File file)
生成的内容会以java文件的方式,存放到你传入File文件的位置