android:[2]代码生成器Javapoet
1、在项目中新建一个java library module名字为app
2、在app的build.gradle中添加javapoet依赖[推荐]
compile 'com.squareup:javapoet:1.7.0'
或者你也可以将javapoet的jar包下载下来直接放入app的libs目录
javapoet的下载地址为http://mvnrepository.com/artifact/com.squareup/javapoet/1.7.0
直接点击Download (JAR)即可下载
3、添加好依赖后刷新一下项目依赖即可生效,
1、接下来我们要生成一个HelloWorld.java
内容为
package com.example.generate;public class HelloWorld {}
在javapoet中.java文件对应JavaFile
class类对应TypeSpec
因此创建HelloWorld类的代码为
TypeSpec typeSpec = TypeSpec.classBuilder("HelloWorld") .addModifiers(Modifier.PUBLIC) .build();
其中classBuilder传入类名,
addModifiers传入修饰语
创建HelloWorld.java的代码为
PACKAGE = "com.example.generate"
JavaFile javaFile = JavaFile.builder(PACKAGE, typeSpec).build();
我们将创建的内容打印到控制台
javaFile.writeTo(System.out);
可以看到输出的内容为
package com.example.generate;
public class HelloWorld {
}
2、一般我们生成的代码最终会保存为文件,
javapoet将生成的代码保存成文件的方法也是调用JavaFile的writeTo方法,
我们直接传入需要保存的目录即可
javaFile.writeTo(new File("app/src/main/java"));
3、HelloWorld.java按照我们的要求生成了,
现在我们将HelloWorld.java的内容改造一下
在HelloWorld.java中添加Parent抽象类
给HelloWorld类添加final修改语,并实现Serializable接口和Parent类并重写Parent的getMessage方法
并添加一个名为message的static final 修饰的String类型变量,变量的值为Hello, JavaPoet!
同时实现main方法,并在方法中通过System.out.println打印Hello, JavaPoet!
我们期望生成的代码如下
package com.example.generate;import java.io.Serializable;public final class HelloWorld extends Parent implements Serializable{ private static final String message = "Hello, JavaPoet!"; public static void main(String[] args){ System.out.println("Hello, JavaPoet!"); } @Override protected String getMessage() { return message; }}abstract class Parent{ protected abstract String getMessage();}
4、首先我们生成protected abstract String getMessage();方法
MethodSpec getMessage = MethodSpec.methodBuilder("getMessage") .addModifiers(Modifier.PROTECTED) .addModifiers(Modifier.ABSTRACT) .returns(String.class) .build();
然后生成Parent类并添加getMessage方法
TypeSpec parent = TypeSpec.classBuilder("Parent") .addModifiers(Modifier.ABSTRACT) .addMethod(getMessage) .build();
这样Parent类的生成代码就写好了
接下来写HelloWorld的实现代码,
首先给HelloWorld添加final修饰,并实现接口和继承Parent类
TypeSpec typeSpec = TypeSpec.classBuilder("HelloWorld") .addModifiers(Modifier.PUBLIC) .addModifiers(Modifier.FINAL) .addSuperinterface(Serializable.class) .build();
接下生成message变量
FieldSpec message = FieldSpec.builder(String.class, "message") .addModifiers(Modifier.PUBLIC, Modifier.STATIC) .addModifiers(Modifier.FINAL) .initializer("\"Hello, JavaPoet!\"") .build();
然后重载getMessage方法,并添加@Override注解
MethodSpec getMessageOvrerride = MethodSpec.methodBuilder("getMessage") .addAnnotation(Override.class) .addModifiers(Modifier.PROTECTED) .returns(String.class) .addStatement("return message") .addModifiers() .build();
再添加main方法,并在main方法中打印字符串
MethodSpec main = MethodSpec.methodBuilder("main") .addModifiers(Modifier.PUBLIC, Modifier.STATIC) .returns(void.class) .addParameter(String[].class, "args") .addStatement("System.out.println(\"Hello, JavaPoet!\")") .build();
最后将生成的main方法,重写的getMessage, 和message字段添加到HelloWorld中
TypeSpec typeSpec = TypeSpec.classBuilder("HelloWorld") .addModifiers(Modifier.PUBLIC) .addModifiers(Modifier.FINAL) .superclass(ClassName.get(PACKAGE, parent.name)) .addSuperinterface(Serializable.class) .addType(parent) .addField(message) .addMethod(main) .addMethod(getMessageOvrerride) .build();
编译运行并查看生成结果,发现生成的代码和预期的有点差别
package com.example.generate;import java.io.Serializable;import java.lang.Override;import java.lang.String;public final class HelloWorld extends Parent implements Serializable { public static final String message = "Hello, JavaPoet!"; public static void main(String[] args) { System.out.println("Hello, JavaPoet!"); } @Override protected String getMessage() { return message; } abstract class Parent { protected abstract String getMessage(); }}
生成的代码变成了HelloWorld的内部类,这并不是我们期望的结果,
查看javapoet文档也没有找到解决方法,通过查看JavaFile代码我们发现只能传入一个TypeSpec,如果要达到我们期望的结果只有自己重新实现JavaFile。
5、步骤4中我们发现TypeSpec.Builder下的addType添加的只能是内部类,并不能实现一个.java文件中并列存在多个类,
这里给出重写的JavaFile实现JavaFileFixed, 重写的类中保存了多个TypeSpec实例,Builder中添加了两个额外的addType方法,
JavaFileFixed代码请到步骤8给的链接中去查看
6、将生成HelloWorld代码中的.addType(parent)方法去掉,应为我们不想Parent类成为HelloWorld的内部类,
同时将JavaFile javaFile = JavaFile.builder(PACKAGE, typeSpec).build();
替换为JavaFileFixed javaFile = JavaFileFixed.builder(PACKAGE, typeSpec).addType(parent).build();
新实现的代码中builder(PACKAGE, typeSpec),typeSpec将作为顶级类,也是.java文件的名字
addType(parent)中的parent将会作为typeSpec的并列类,更具java语法一个.java文件中只能有一个public顶积类,因此parent不能是public的,
以下是修改后的代码
MethodSpec getMessage = MethodSpec.methodBuilder("getMessage") .addModifiers(Modifier.PROTECTED) .addModifiers(Modifier.ABSTRACT) .returns(String.class) .build();TypeSpec parent = TypeSpec.classBuilder(ClassName.get(PACKAGE, "Parent")) .addModifiers(Modifier.ABSTRACT) .addMethod(getMessage) .build();FieldSpec message = FieldSpec.builder(String.class, "message") .addModifiers(Modifier.PUBLIC, Modifier.STATIC) .addModifiers(Modifier.FINAL) .initializer("\"Hello, JavaPoet!\"") .build();MethodSpec getMessageOvrerride = MethodSpec.methodBuilder("getMessage") .addAnnotation(Override.class) .addModifiers(Modifier.PROTECTED) .returns(String.class) .addStatement("return message") .addModifiers() .build();MethodSpec main = MethodSpec.methodBuilder("main") .addModifiers(Modifier.PUBLIC, Modifier.STATIC) .returns(void.class) .addParameter(String[].class, "args") .addStatement("System.out.println(\"Hello, JavaPoet!\")") .build();TypeSpec typeSpec = TypeSpec.classBuilder("HelloWorld") .addModifiers(Modifier.PUBLIC) .addModifiers(Modifier.FINAL) .superclass(ClassName.get(PACKAGE, parent.name)) .addSuperinterface(Serializable.class) //.addType(parent) .addField(message) .addMethod(main) .addMethod(getMessageOvrerride) .build();JavaFileFixed javaFile = JavaFileFixed.builder(PACKAGE, typeSpec).addType(parent).build();try { javaFile.writeTo(new File("app/src/main/java"));} catch (IOException e) { e.printStackTrace();}
7、修改后重新编译运行查看结果
package com.example.generate;import java.io.Serializable;import java.lang.Override;import java.lang.String;public final class HelloWorld extends Parent implements Serializable { public static final String message = "Hello, JavaPoet!"; public static void main(String[] args) { System.out.println("Hello, JavaPoet!"); } @Override protected String getMessage() { return message; }}abstract class Parent { protected abstract String getMessage();}
与我们预期的效果一致
8、文章中所有源代码:https://git.oschina.net/jackyanngo/JavaPoetSample.git