文档章节

Javapoet源码解析

o
 osc_z1hvg4cu
发布于 2018/04/24 15:44
字数 1012
阅读 9
收藏 0

Javapoet:是生成.java源文件的开源API

 以生成一个HelloWrold.java文件为例:

1 package com.example.helloworld;
2 
3 public final class HelloWorld {
4   public static void main(String[] args) {
5     System.out.println("Hello, JavaPoet!");
6   }
7 }
 1 MethodSpec main = MethodSpec.methodBuilder("main")
 2     .addModifiers(Modifier.PUBLIC, Modifier.STATIC)
 3     .returns(void.class)
 4     .addParameter(String[].class, "args")
 5     .addStatement("$T.out.println($S)", System.class, "Hello, JavaPoet!")
 6     .build();
 7 
 8 TypeSpec helloWorld = TypeSpec.classBuilder("HelloWorld")
 9     .addModifiers(Modifier.PUBLIC, Modifier.FINAL)
10     .addMethod(main)
11     .build();
12 
13 JavaFile javaFile = JavaFile.builder("com.example.helloworld", helloWorld)
14     .build();
15 
16 ///javaFile.writeTo(System.out);  //System.out print  to the console
17  //generate a java file in user.dir
18 String directory = System.getProperty("user.dir");
File file = new File(directory + SEPARATOR + "HelloWrold.java"); 22 PrintStream ps = new PrintStream(new FileOutputStream(file)); 23 javaFile.writeTo(ps); 24 ps.flush(); 25 ps.close();

在这个例子中用到了三个类的对象 :JavaFile  MethodSpec   TypeSpec,首先来看第一个JavaFile

1  public static Builder builder(String packageName, TypeSpec typeSpec) {
2     checkNotNull(packageName, "packageName == null");
3     checkNotNull(typeSpec, "typeSpec == null");
4     return new Builder(packageName, typeSpec);
5   }

Builder是JavaFile中的一个静态内部类,由此可以看到 Javapoet使用的是建造者设计模式。通过packageName 和TypeSpec生成一个Builder对象,然后调用Builder类的build方法:

1 public JavaFile build() {
2       return new JavaFile(this);
3     }

返回当前的JavaFile对象,然后调用writeto方法将该对象写入流/文件。

接下来看看构造Builder方法时使用的TypeSpec是什么。

staticBlock:A generated class, interface, or enum declaration:对于要生成的类,接口或枚举的声明。就是定义 类 接口或者枚举,定义的时候需要给他们命名,添加权限修饰符 是否静态 是否抽象 是否final,添加方法等操作

所以这个类里面有静态方法classBuilder interfaceBuilder enumBuilder 以及匿名内部类anonymousClassBuilder,这些静态方法都返回对应的一个Builder对象

该Builder对象是TypeSpec中的静态内部类,用于构建当前的TypeSpec对象。在内部类Builder中应该有添加权限修饰符/注释/注解/变量等操作来构建一个类或者接口枚举

MethodSpec:A generated constructor or method declaration. 对方法的声明,包括构造方法。所以这个类里面有methodBuilder constructorBuilder,返回该类的一个Builder对象,这个builder也是该类的一个静态内部类。并且这个Builder内部类中同样包括添加权限修饰符/注释/注解等方法,另外方法有返回值,参数 Comment 语句来构建一个方法

同样的原理,FieldSpec是对成员变量的声明,而且里面也有一个可以返回当前对象的builder静态内部类,在这个builder中同样有添加注释注解访问修饰符等的操作,来构建一个变量。

类变量等已经定义完毕,接下来我们分析一下是如何生成java文件的,回到JavaFile的writeTo方法

这里有很多重载的writeTo方法,最终都会调用

 1  public void writeTo(Appendable out) throws IOException {
 2     // First pass: emit the entire class, just to collect the types we'll need to import.
 3     CodeWriter importsCollector = new CodeWriter(NULL_APPENDABLE, indent, staticImports);
 4     emit(importsCollector);
 5     Map<String, ClassName> suggestedImports = importsCollector.suggestedImports();
 6 
 7     // Second pass: write the code, taking advantage of the imports.
 8     CodeWriter codeWriter = new CodeWriter(out, indent, suggestedImports, staticImports);
 9     emit(codeWriter);
10   }
CodeWriter是什么呢?CodeWriter将JavaFile转换为适用于人类和javac使用的字符串,实现了导入,缩进和延期变量名称。

以FieldSpec为例来说明CodeWriter的用法:

 1 void emit(CodeWriter codeWriter, Set<Modifier> implicitModifiers) throws IOException {
 2     codeWriter.emitJavadoc(javadoc);
 3     codeWriter.emitAnnotations(annotations, false);
 4     codeWriter.emitModifiers(modifiers, implicitModifiers);
 5     codeWriter.emit("$T $L", type, name);
 6     if (!initializer.isEmpty()) {
 7       codeWriter.emit(" = ");
 8       codeWriter.emit(initializer);
 9     }
10     codeWriter.emit(";\n");
11   }

这段代码是在生成变量时调用的。第二行是写javadoc注释,第三行是写注解,第四行是写访问修饰符,第五行是写该变量的类型和变量名,第6-9行是判断变量是否有初始化值,如果有就写初始化值

第10行;代表该变量写出完毕。至此,HelloWorld.java的生成过程分析完毕。

 

用到的一些集合类中的方法:

Collections.singletonList

Collections.emptyList()

EnumSet.copyOf(Set<Modifier> modifiers)

Collections.unmodifiableList(new ArrayList<>(collection));   返回指定列表的不可修改视图。 此方法允许模块为用户提供对内部列表的“只读”访问权限。

上一篇: 匿名内存 | shm
o
粉丝 0
博文 500
码字总数 0
作品 0
私信 提问
加载中
请先登录后再评论。

暂无文章

OSChina 周五乱弹 —— 你大妈还是你大妈

Osc乱弹歌单(2020)请戳(这里) 【今日歌曲】 @watergood:是时候分享一波我的这张纯音乐歌单了,过去的五年多时间里,我陆陆续续地把听到的好听的纯音乐添加了进去,目前一共65首,相信总...

小小编辑
今天
19
0
在Objective-C中生成随机数 - Generating random numbers in Objective-C

问题: I'm a Java head mainly, and I want a way to generate a pseudo-random number between 0 and 74. In Java I would use the method: 我主要是Java头,我想要一种生成0到74之间的伪随......

技术盛宴
今天
13
0
ftp-ftps-sftp的关系

Ftp FTP 是File Transfer Protocol(文件传输协议)的英文简称,而中文简称为“文传协议”。用于Internet上的控制文件的双向传输。同时,它也是一个应用程序(Application)。基于不同的操作...

独钓渔
今天
12
0
使Vim将所有空格显示为字符 - Make Vim show ALL white spaces as a character

问题: I can't find a way to make Vim show all white spaces as a character. 我找不到让Vim将所有空白显示为字符的方法。 All I found was about tabs, trailing spaces etc. 我发现的只......

富含淀粉
今天
23
0
RN 接入高德地图遇到的一些问题

react-native-amap-geolocation、react-native-amap3d 1、iOS Geolocation.getCurrentPosition 获取坐标后,没有返回 address 信息? 逆地理编码 Android 默认返回逆地理编码,而 iOS 需要手...

Jack088
今天
14
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部