javapoet简介
javapoet是一个用于生成.java源文件的Java API。相关的还有javaWriter是javapoet的一个分支,ASM是一个java字节码操纵框架,它能被用来动态生成类或者增强既有类的功能。ASM 可以直接产生二进制 class 文件,也可以在类被加载入 Java 虚拟机之前动态改变类行为。javapoet常用来做编译时java文件生成,在butterknife和dagger中使用。
javapoet中API的使用
1.我们动态生成类使用TypeSpec.classBuilder()方法,在classBuilder方法中参数类型为String或者ClassName,就是生成class类的名称,ClassName是JavaPoet中定义的一个对象,可以通过ClassName.get()获取,在这个里面可以传入包名和类名组成一个全路径名称,ClassName.get(“www.hikvision.com”,TestBuilder)组成一个www.hikvision.com.TestBuilder全路径名。
TypeSpec build = TypeSpec.classBuilder("TestBuilder")
.build();
String path = Main.class.getResource("/").getPath();
File file = new File(path);
JavaFile.builder("www.hikvision.com",build).build().writeTo(file);
#
在上面classBuilder中是类的名称,JavaFile.builder(“www.hikvision.com”,build).build().writeTo(file);”www.hikvision.com”是包名。生成文件如下
package www.hikvision.com;
class TestBuilder {
}
2.可以通过修饰符来修饰一个类,Modifier是修饰符枚举,里面定义了 PUBLIC,PROTECTED,PRIVATE,ABSTRACT,DEFAULT,STATIC,FINAL,
TRANSIENT,VOLATILE,SYNCHRONIZED,NATIVE,STRICTFP;12个修饰符类addModifiers()方法调用
TypeSpec build = TypeSpec.classBuilder("TestBuilder")
.addModifiers(Modifier.ABSTRACT,Modifier.PUBLIC,Modifier.STATIC)
.build();
3.在生成类中添加字段,通过FieldSpec.builder()来生成字段,在builder定义字段的类型,名称和修饰符,再通过addFiled()添加到类中
TypeSpec build = TypeSpec.classBuilder("TestBuilder")
.addModifiers(Modifier.ABSTRACT,Modifier.PUBLIC,Modifier.STATIC)
.addField(FieldSpec.builder(TypeName.BOOLEAN,"isOpen",Modifier.PROTECTED).build())
.build();
4.构造方法的添加,通过addMethod()方法添加一个MethodSpec对象,可以通过MethodSpec.constructorBuilder()生成一个构造方法,也可生通过MethodSpec.methodBuilder()成一个普通方法,记得在生成构造方法时通过修饰符addModifiers()修饰构造方法
TypeSpec build = TypeSpec.classBuilder("TestBuilder")
.addModifiers(Modifier.ABSTRACT,Modifier.PUBLIC,Modifier.STATIC)
.addMethod(MethodSpec.constructorBuilder().addModifiers(Modifier.PUBLIC).build())
.build();
5.生成类中使用泛型,使用addTypeVariable方法,可以通过添加TypeVariableName来设置类的泛型
TypeVariableName typeVariableName=TypeVariableName.get(“T”);
TypeSpec build = TypeSpec.classBuilder("TestBuilder")
.addModifiers(Modifier.ABSTRACT,Modifier.PUBLIC,Modifier.STATIC)
.addTypeVariable(typeVariableName)
.build();
6.泛型约束例如,还是可以通过TypeVariableName来设置
TypeVariableName typeVariableName=TypeVariableName.get("T",TypeName.get(Main.class));
TypeSpec build = TypeSpec.classBuilder("TestBuilder")
.addModifiers(Modifier.ABSTRACT,Modifier.PUBLIC,Modifier.STATIC)
.addTypeVariable(typeVariableName)
.build();
7.实现接口通过addSuperinterface()方法实现接口实现
TypeSpec build = TypeSpec.classBuilder("TestBuilder")
.addModifiers(Modifier.ABSTRACT,Modifier.PUBLIC,Modifier.STATIC)
.addSuperinterface(ITest.class)
.build();
8.继承类superclass()
TypeSpec build = TypeSpec.classBuilder("TestBuilder")
.addModifiers(Modifier.ABSTRACT,Modifier.PUBLIC,Modifier.STATIC)
.superclass(Test.class)
.build();
9.接口泛型约束 public class A implement B{}这种在接口上面添加泛型约束,通过addSuperinterface()方法和ParameterizedTypeName结合使用,通过ParameterizedTypeName包裹接口类和泛型来实现
ParameterizedTypeName
parameterizedTypeName=ParameterizedTypeName.get(ITest.class,Main.class);
TypeSpec build = TypeSpec.classBuilder("TestBuilder")
.addModifiers(Modifier.ABSTRACT,Modifier.PUBLIC,Modifier.STATIC)
.addSuperinterface(parameterizedTypeName)
.build();
10.普通方法添加通过addMethod方法,使用MethodSpec.methodBuilder()添加方法
MethodSpec testMethod = MethodSpec.methodBuilder("test")
.addModifiers(Modifier.PUBLIC)
.build();
TypeSpec build = TypeSpec.classBuilder("TestBuilder")
.addModifiers(Modifier.ABSTRACT,Modifier.PUBLIC,Modifier.STATIC)
.addMethod(testMethod)
.build();
11.返回值添加是MethodSpec.returns()
MethodSpec testMethod = MethodSpec.methodBuilder("test")
.addModifiers(Modifier.PUBLIC)
.returns(Main.class)
.build();
12.方法参数添加MethodSpec.addParameter
CodeBlock codeBlock=CodeBlock.builder()
.add("T temp=t;\n")
.build();
MethodSpec testMethod = MethodSpec.methodBuilder("test")
.addModifiers(Modifier.PUBLIC)
.addParameter(typeVariableName,"t")
.build();
13.Map泛型使用
Map<String, Class<? extends IRouteGroup>>
ParameterizedTypeName inputMapTypeOfRoot = ParameterizedTypeName.get(
ClassName.get(Map.class),
ClassName.get(String.class),
ParameterizedTypeName.get(
ClassName.get(Class.class),
WildcardTypeName.subtypeOf(ClassName.get(type_IRouteGroup))
)
);
14.代码块$L使用
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 = $L; i < $L; i++)", from, to)
.addStatement("result = result $L i", op)
.endControlFlow()
.addStatement("return result")
.build();
}
代码块添加有两种方法addCode()和addStatement()两种方式,在addCode中可以创建一个CodeBlock代码块添加代码,在生成代码块是可以使用format对代码进行替换,在javapoet中主要用 T, N四种, S主要替换字符串, N替换名字,一般调用方法可以通过$N替换。https://github.com/square/javapoet这个是javapoet在github托管网址,有javapoet基础用法,关于泛型使用没有讲解,可以学习butterknife中泛型使用https://github.com/JakeWharton/butterknife,也可以看下我GitHub关于编译时注解demo,https://github.com/starsquare/star_sky里面有相关泛型的引用。
CodeBlock codeBlock=CodeBlock.builder()
.add("T temp=t;\n")
.build();
MethodSpec testMethod = MethodSpec.methodBuilder("test")
.addModifiers(Modifier.PUBLIC)
.addCode(codeBlock)
.addStatement("$T m=new $T()",Main.class,Main.class)
.build();