【参考链接】
JavaPoet的基本使用http://blog.****.net/crazy1235/article/details/51876192
javapoet——让你从重复无聊的代码中解放出来http://www.jianshu.com/p/95f12f72f69a
在看ButterKnife的时候提到JavaPoet,就去看了一下。
是Square的一个开源项目,https://github.com/square/javapoet,用于生成.java源代码文件。已经有文章翻译了他的readme,见参考链接。
下面的示例代码都以javapoet-1.9.0.jar为例
基本使用方式如下
MethodSpecmain = MethodSpec.methodBuilder("main")// main代表方法名 .addModifiers(Modifier.PUBLIC, Modifier.STATIC)// Modifier//注意类型为javax.lang.model.element.Modifier .addParameter(String[].class,"args")//添加string[]类型的名为args的参数 .addStatement("$T.out.println($S)", System.class,"Hello World")//添加代码 .build();
TypeSpechelloWorld = TypeSpec.classBuilder("HelloWorld") .addModifiers(Modifier.PUBLIC) .addField(String.class,"greeting", Modifier.PRIVATE, Modifier.FINAL) .addMethod(main).build();
JavaFilejavaFile = JavaFile.builder("com.example.helloworld",helloWorld).build();
try { javaFile.writeTo(System.out); }catch (IOExceptione) { e.printStackTrace(); } |
生成的源代码文件如下
TypeSpec
即可以生成类,也可能生成接口和枚举等
上面是使用classBuilder来生成类,还可以使用interfaceBuilder来生成接口
TypeSpechelloWorld = TypeSpec.interfaceBuilder("HelloWorld").addModifiers(Modifier.PUBLIC) .addField(FieldSpec.builder(String.class,"ONLY_THING_THAT_IS_CONSTANT") .addModifiers(Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL).initializer("$S","change") .build()) .addMethod(MethodSpec.methodBuilder("beep") .addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT) .build()) .build(); |
使用enumBuilder来生成枚举类
TypeSpechelloWorld = TypeSpec.enumBuilder("Roshambo") .addModifiers(Modifier.PUBLIC) .addEnumConstant("ROCK") .addEnumConstant("SCISSORS") .addEnumConstant("PAPER") .build(); |
FieldSpec
可以通过initializer来指定成员变量的初始值
FieldSpecandroid = FieldSpec.builder(String.class,"android") .addModifiers(Modifier.PRIVATE, Modifier.FINAL) .initializer("$S + $L","Lollipop v.", 5.0d)//可以使用initializer构造初始值 .build(); |
MethodSpec
可以使用addStatement来添加代码片段(并且在其中使用$占位符)
publicclass MethodSpecDemo { privatestatic MethodSpec computeRange(Stringname,intfrom,intto, Stringop) { return MethodSpec.methodBuilder(name) .returns(int.class) .addStatement("int result = 0") .beginControlFlow("for (int i = $L; i < $L; i++)",from,to)//注意这个地方得是$L .addStatement("result = result $L i",op) .endControlFlow() .addStatement("return result") .build(); }
publicstaticvoid main(String[]args) { 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();
try { javaFile.writeTo(System.out); } catch (IOExceptione) { e.printStackTrace(); }
} } |
还可以直接通过constructorBuilder来生成类的构造函数,此时可以省略指定方法名
MethodSpecflux = MethodSpec.constructorBuilder()//生成构造函数时可以省略指定方法名 .addModifiers(Modifier.PUBLIC) .addParameter(String.class,"greeting") .addStatement("this.$L = $L","greeting","greeting") .build();
TypeSpechelloWorld = TypeSpec.classBuilder("HelloWorld") .addModifiers(Modifier.PUBLIC) .addField(String.class,"greeting", Modifier.PRIVATE, Modifier.FINAL) .addMethod(flux) .build();
JavaFilejavaFile = JavaFile.builder("com.example.helloworld",helloWorld).build();
try { javaFile.writeTo(System.out); }catch (IOExceptione) { e.printStackTrace(); } |
ParameterSpec
这个其实就是把MethodSpec中的参数单独拿出来构造
ParameterSpecandroid = ParameterSpec.builder(String.class,"android") .addModifiers(Modifier.FINAL) .build();
MethodSpecwelcomeOverlords = MethodSpec.methodBuilder("welcomeOverlords") .addParameter(android)//添加方法定义中的参数 .addParameter(String.class,"robot", Modifier.FINAL) .build(); |
$
在前面的
FieldSpec.Builder.initializer()和
MethodSpec.Builder.addStatement()、MethodSpec.Builder. beginControlFlow()中已经使用过$占位符
$S/$L
$S是用后面的字符串替换前面表达式中的占位符,并且还会带双引号“”
$L是用后面的各种类型替换前面表达式中的占位符,并且不带双引号””
$T
可以使用$T来指代源代码中的数据类型,并且此时会自动import导入相应的类型。
参数既可以传递Class类型,也可以传递com.squareup.javapoet.ClassName类型。
传递Class类型的示例如下
MethodSpectoday = MethodSpec.methodBuilder("today") .returns(Date.class) .addStatement("return new $T()", Date.class) .build();
TypeSpechelloWorld = TypeSpec.classBuilder("HelloWorld") .addModifiers(Modifier.PUBLIC, Modifier.FINAL) .addMethod(today) .build(); |
传递com.squareup.javapoet.ClassName类型的示例如下
//也可以传递ClassName来当类型名称 ClassNamehoverboard = ClassName.get("com.mattel","Hoverboard");
MethodSpectoday = MethodSpec.methodBuilder("tomorrow") .returns(hoverboard) .addStatement("return new $T()",hoverboard) .build();
//ClassName叠加泛型//TypeName ClassNamelist = ClassName.get("java.util","List"); ClassNamearrayList = ClassName.get("java.util","ArrayList"); TypeNamelistOfHoverboards = ParameterizedTypeName.get(list,hoverboard);
MethodSpecbeyond = MethodSpec.methodBuilder("beyond") .returns(listOfHoverboards) .addStatement("$T result = new $T<>()",listOfHoverboards,arrayList) .addStatement("result.add(new $T())",hoverboard) .addStatement("result.add(new $T())",hoverboard) .addStatement("result.add(new $T())",hoverboard) .addStatement("return result") .build();
TypeSpechelloWorld = TypeSpec.classBuilder("HelloWorld") .addModifiers(Modifier.PUBLIC, Modifier.FINAL) .addMethod(today) .addMethod(beyond) .build(); |
此外还有使用$N来指代方法名,不过因为也可以使用$L来实现,故这里不再举例。