Javapoet源码解析
Posted 贵在坚持
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Javapoet源码解析相关的知识,希望对你有一定的参考价值。
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)); 返回指定列表的不可修改视图。 此方法允许模块为用户提供对内部列表的“只读”访问权限。
以上是关于Javapoet源码解析的主要内容,如果未能解决你的问题,请参考以下文章