JavaPoet的基本使用.docx
- 文档编号:10515350
- 上传时间:2023-05-26
- 格式:DOCX
- 页数:22
- 大小:21.36KB
JavaPoet的基本使用.docx
《JavaPoet的基本使用.docx》由会员分享,可在线阅读,更多相关《JavaPoet的基本使用.docx(22页珍藏版)》请在冰点文库上搜索。
JavaPoet的基本使用
JavaPoet的基本使用
JavaPoet
JavaPoet是一个用来生成.Java源文件的JavaAPI。
当做如注解或者数据库模式、协议格式等事情时,生成源文件就比较有用处。
Example
以HelloWorld类为例:
packagecom.example.helloworld;
publicfinalclassHelloWorld{
publicstaticvoidmain(String[]args){
System.out.println("Hello,JavaPoet!
");
}
上面的代码就是使用javapoet用下面的代码进行生成的:
MethodSpecmain=MethodSpec.methodBuilder("main")
.addModifiers(Modifier.PUBLIC,Modifier.STATIC)
.returns(void.class)
.addParameter(String[].class,"args")
.addStatement("$T.out.println($S)",System.class,"Hello,JavaPoet!
")
.build();
TypeSpechelloWorld=TypeSpec.classBuilder("HelloWorld")
.addModifiers(Modifier.PUBLIC,Modifier.FINAL)
.addMethod(main)
.build();
JavaFilejavaFile=JavaFile.builder("com.example.helloworld",helloWorld)
.build();
javaFile.writeTo(System.out);
通过MethodSpec类来创建一个”main”方法,并配置了修饰符、返回值类型、参数以及代码语句。
然后把这个main方法添加到HelloWorld类中,最后添加到HelloWorld.java文件中。
这个例子中,我们将文件通过Sytem.out进行输出,但是同样也可以使用(JavaFile.toString())得到string字符串,或者通过(JavaPoet.writeTo())方法写入到文件系统中。
Javadoc中包括了完整的JavaPoetAPI,我们接着往下看。
Code&ControlFlow
大多数JavaPoet的API使用的是简单的不可变的Java对象。
通过建造者模式,链式方法,可变参数是的API比较友好。
JavaPoet提供了(TypeSpec)用于创建类或者接口,(FieldSpec)用来创建字段,(MethodSpec)用来创建方法和构造函数,(ParameterSpec)用来创建参数,(AnnotationSpec)用于创建注解。
但是如果没有语句类,没有语法结点数,可以通过字符串来构建代码块:
MethodSpecmain=MethodSpec.methodBuilder("main")
.addCode(""
+"inttotal=0;\n"
+"for(inti=0;i<10;i++){\n"
+"total+=i;\n"
+"}\n")
.build();
生成的代码如下:
voidmain(){
inttotal=0;
for(inti=0;i<10;i++){
total+=i;
}
}
人为的输入分号、换行和缩进是比较乏味的。
所以JavaPoet提供了相关API使它变的容易。
addStatement()负责分号和换行,beginControlFlow()+endControlFlow()需要一起使用,提供换行符和缩进。
MethodSpecmain=MethodSpec.methodBuilder("main")
.addStatement("inttotal=0")
.beginControlFlow("for(inti=0;i<10;i++)")
.addStatement("total+=i")
.endControlFlow()
.build();
这个例子稍微有点差劲。
生成的代码如下:
privateMethodSpeccomputeRange(Stringname,intfrom,intto,Stringop){
returnMethodSpec.methodBuilder(name)
.returns(int.class)
.addStatement("intresult=0")
.beginControlFlow("for(inti="+from+";i<"+to+";i++)")
.addStatement("result=result"+op+"i")
.endControlFlow()
.addStatement("returnresult")
.build();
}
调用computeRange("multiply10to20",10,20,"*")就生成如下代码:
intmultiply10to20(){
intresult=0;
for(inti=10;i<20;i++){
result=result*i;
}
returnresult;
}
方法生成方法!
JavaPoet生成的是源代码而不是字节码,所以可以通过阅读源码确保正确。
$LforLiterals
字符串连接的方法beginControlFlow()和addStatement是分散开的,操作较多。
针对这个问题,JavaPoet提供了一个语法但是有违String.format()语法.通过$L来接受一个literal值。
这有点像Formatter’s%s:
privateMethodSpeccomputeRange(Stringname,intfrom,intto,Stringop){
returnMethodSpec.methodBuilder(name)
.returns(int.class)
.addStatement("intresult=0")
.beginControlFlow("for(inti=$L;i<$L;i++)",from,to)
.addStatement("result=result$Li",op)
.endControlFlow()
.addStatement("returnresult")
.build();
}
Literals直接写在输出代码中,没有转义。
它的类型可以是字符串、primitives和一些接下来要说的JavaPoet类型。
$SforStrings
当输出的代码包含字符串的时候,可以使用$S表示一个string。
下面的代码包含三个方法,每个方法返回自己的名字:
publicstaticvoidmain(String[]args)throwsException{
TypeSpechelloWorld=TypeSpec.classBuilder("HelloWorld")
.addModifiers(Modifier.PUBLIC,Modifier.FINAL)
.addMethod(whatsMyName("slimShady"))
.addMethod(whatsMyName("eminem"))
.addMethod(whatsMyName("marshallMathers"))
.build();
JavaFilejavaFile=JavaFile.builder("com.example.helloworld",helloWorld)
.build();
javaFile.writeTo(System.out);
}
privatestaticMethodSpecwhatsMyName(Stringname){
returnMethodSpec.methodBuilder(name)
.returns(String.class)
.addStatement("return$S",name)
.build();
}
输出结果如下:
publicfinalclassHelloWorld{
StringslimShady(){
return"slimShady";
}
Stringeminem(){
return"eminem";
}
StringmarshallMathers(){
return"marshallMathers";
}
$TforTypes
使用Java内置的类型会使代码比较容易理解。
JavaPoet极大的支持这些类型,通过$T进行映射,会自动import声明。
MethodSpectoday=MethodSpec.methodBuilder("today")
.returns(Date.class)
.addStatement("returnnew$T()",Date.class)
.build();
TypeSpechelloWorld=TypeSpec.classBuilder("HelloWorld")
.addModifiers(Modifier.PUBLIC,Modifier.FINAL)
.addMethod(today)
.build();
JavaFilejavaFile=JavaFile.builder("com.example.helloworld",helloWorld)
.build();
javaFile.writeTo(System.out);
自动完成import声明,生成代码如下:
packagecom.example.helloworld;
importjava.util.Date;
publicfinalclassHelloWorld{
Datetoday(){
returnnewDate();
}
}
再举一个相似的例子,但是应用了一个不存在的类:
ClassNamehoverboard=ClassName.get("com.mattel","Hoverboard");
MethodSpectoday=MethodSpec.methodBuilder("tomorrow")
.returns(hoverboard)
.addStatement("returnnew$T()",hoverboard)
.build();
类不存在,但是代码是完整的:
packagecom.example.helloworld;
importcom.mattel.Hoverboard;
publicfinalclassHelloWorld{
Hoverboardtomorrow(){
returnnewHoverboard();
}
}
ClassName这个类非常重要,当你使用JavaPoet的时候会频繁的使用它。
它可以识别任何声明类。
具体看下面的例子:
ClassNamehoverboard=ClassName.get("com.mattel","Hoverboard");
ClassNamelist=ClassName.get("java.util","List");
ClassNamearrayList=ClassName.get("java.util","ArrayList");
TypeNamelistOfHoverboards=ParameterizedTypeName.get(list,hoverboard);
MethodSpecbeyond=MethodSpec.methodBuilder("beyond")
.returns(listOfHoverboards)
.addStatement("$Tresult=new$T<>()",listOfHoverboards,arrayList)
.addStatement("result.add(new$T())",hoverboard)
.addStatement("result.add(new$T())",hoverboard)
.addStatement("result.add(new$T())",hoverboard)
.addStatement("returnresult")
.build();
JavaPoet将每一种类型进行分解,并尽可能的导入其声明.
packagecom.example.helloworld;
importcom.mattel.Hoverboard;
importjava.util.ArrayList;
importjava.util.List;
publicfinalclassHelloWorld{
List
List
result.add(newHoverboard());
result.add(newHoverboard());
result.add(newHoverboard());
returnresult;
}
Importstatic
JavaPoet支持importstatic。
它显示的收集类型成员的名称。
例子如下:
...
ClassNamenamedBoards=ClassName.get("com.mattel","Hoverboard","Boards");
MethodSpecbeyond=MethodSpec.methodBuilder("beyond")
.returns(listOfHoverboards)
.addStatement("$Tresult=new$T<>()",listOfHoverboards,arrayList)
.addStatement("result.add($T.createNimbus(2000))",hoverboard)
.addStatement("result.add($T.createNimbus(\"2001\"))",hoverboard)
.addStatement("result.add($T.createNimbus($T.THUNDERBOLT))",hoverboard,namedBoards)
.addStatement("$T.sort(result)",Collections.class)
.addStatement("returnresult.isEmpty()$T.emptyList():
result",Collections.class)
.build();
TypeSpechello=TypeSpec.classBuilder("HelloWorld")
.addMethod(beyond)
.build();
JavaFile.builder("com.example.helloworld",hello)
.addStaticImport(hoverboard,"createNimbus")
.addStaticImport(namedBoards,"*")
.addStaticImport(Collections.class,"*")
.build();
JavaPoet将会首先添加importstatic代码块进行配置,当然也需要导入其他所需的类型引用。
packagecom.example.helloworld;
importstaticcom.mattel.Hoverboard.Boards.*;
importstaticcom.mattel.Hoverboard.createNimbus;
importstaticjava.util.Collections.*;
importcom.mattel.Hoverboard;
importjava.util.ArrayList;
importjava.util.List;
classHelloWorld{
List
List
result.add(createNimbus(2000));
result.add(createNimbus("2001"));
result.add(createNimbus(THUNDERBOLT));
sort(result);
returnresult.isEmpty()?
emptyList():
result;
}
$NforNames
使用$N可以引用另外一个通过名字生成的声明。
publicStringbyteToHex(intb){
char[]result=newchar[2];
result[0]=hexDigit((b>>>4)&0xf);
result[1]=hexDigit(b&0xf);
returnnewString(result);
}
publiccharhexDigit(inti){
return(char)(i<10?
i+'0':
i-10+'a');
}
生成的代码如下,在byteToHex()方法中通过$N来引用hexDigit()方法作为一个参数:
MethodSpechexDigit=MethodSpec.methodBuilder("hexDigit")
.addParameter(int.class,"i")
.returns(char.class)
.addStatement("return(char)(i<10?
i+'0':
i-10+'a')")
.build();
MethodSpecbyteToHex=MethodSpec.methodBuilder("byteToHex")
.addParameter(int.class,"b")
.returns(String.class)
.addStatement("char[]result=newchar[2]")
.addStatement("result[0]=$N((b>>>4)&0xf)",hexDigit)
.addStatement("result[1]=$N(b&0xf)",hexDigit)
.addStatement("returnnewString(result)")
.build();
Methods
上面的例子中的方法都有方法体。
使用Modifiers.ABSTRACT创建的方法是没有方法体的。
通常用来创建一个抽象类或接口。
MethodSpecflux=MethodSpec.methodBuilder("flux")
.addModifiers(Modifier.ABSTRACT,Modifier.PROTECTED)
.build();
TypeSpechelloWorld=TypeSpec.classBuilder("HelloWorld")
.addModifiers(Modifier.PUBLIC,Modifier.ABSTRACT)
.addMethod(flux)
.build();
生成如下代码:
publicabstractclassHelloWorld{
protectedabstractvoidflux();
}
当执行修饰符的时。
JavaPoet用的是
javax.lang.model.element.Modifier类,这个类在Android平台上不可用.这只限制与生成代码阶段;输出的代码可运行在任何平台上:
JVMs,Android,
andGWT。
方法可能会有参数,异常,可变参数,注释,注解,类型变量和一个返回类型。
这些都可以通过MethodSpec.Builder来进行配置。
Constructors
MethodSpec也可以用来创建构造函数:
MethodSpecflux=MethodSpec.constructorBuilder()
.addModifiers(Modifier.PUBLIC)
.addParameter(String.class,"greeting")
.addStatement("this.$N=$N","greeting","greeting")
.build();
TypeSpechelloWorld=TypeSpec.classBuilder("HelloWorld")
.addModifiers(Modifier.PUBLIC)
.addField(String.class,"greeting",Modifier.PRIVATE,Modifier.FINAL)
.addMethod(flux)
.build();
生成如下代码:
publicclassHelloWorld{
privatefinalStringgreeting;
publicHelloWorld(Stringgreeting){
this.greeting=greeting;
}
}
多数情况下,构造方法同普通方法一样。
当生成代码时,构造函数会先于其他方法生成。
Parameters
通过ParameterSpec.builder()可以创建参数,或者直接调用MethodSpec类的addParameter()方法添加参数:
ParameterSpecandroid=ParameterSpec.builder(String.class,"android")
.addModifiers(Modifier.FINAL)
.build();
MethodSpecwelcomeOverlords=MethodSpec.methodBuilder("welcomeOverlords
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- JavaPoet 基本 使用