Jdeparser学习笔记
Jdeparser简介
Jdeparser是JBOSS社区提供的Java源代码生成工具,可以方便生成Java源代码,常用于Annotation Processing中。
Jdeparser常用类
JDeparser
JDeparser类是JDeparser的入口,通过调用createSources函数创建JSources(源码容器)
JSources
JSources是源码容器,通过createSourceFile函数可以创建JSourceFile(源码文件)
JSourceFile
JSourceFile是源码文件,该类包含以下几个函数,用于创建源文件具体内容:
- _import 生成iimport语句
- importStatic 生成import语句(import类中的静态变量)
- blankLine 添加一个空行
- _class 生成class
- _enum 生成枚举类型
- _interface 生成接口
- annotationInterface 生成注解接口
_class, _enum, _interface, annotationInterface四个函数会返回JClassDef对象
JClassDef
JClassDef是类定义, 通过该类的一系列函数完成类具体内容定义:
- _extends 类继承哪个类
- _implements 类实现哪些接口
- erasedType 获取当前类擦除类型后的类型
- genericType 获取当前
- _enum 生成枚举值(该函数不会生成name, 可能是一个bug)
- typeParam 生成泛型信息
- method 生成方法
- annotate 生成类上的注解
- field 生成类属性
- constructor 生成构造函数
- staticInit 生成static静态代码块
- init 生成代码块(与staticInit不同, 每次new的时候都会执行init, 看看成构造函数的一部分)
Filer
文件编档员,用于存储JSources, 比如存储JSources到文件, 或者存储到ByteArrayOutputStream中
private final JFiler filer = new JFiler() {
public OutputStream openStream(final String packageName, final String fileName) throws IOException {
final Key key = new Key(packageName, fileName + ".java");
if (!sourceFiles.containsKey(key)) {
final ByteArrayOutputStream stream = new ByteArrayOutputStream();
if (sourceFiles.putIfAbsent(key, stream) == null) {
return stream;
}
}
throw new IOException("Already exists");
}
};
FormatPreferences
生成源文件的格式配置, 比如空格个数等
组件示例
生成一个类
JSources sources = JDeparser.createSources(getFiler(), new FormatPreferences());
JSourceFile bazFile = sources.createSourceFile("org.foo.bar", "Baz");
导入类
#import java.math.BigDecimal;
bazFile._import(BigDecimal.class);
生成类
//@Controller
//public class Baz<T extends String> extends XXClass implements XXInterface1, XXInterface2{}
JClassDef classDef = bazFile._class(JMod.PUBLIC, "Baz");
classDef.typeParam("T")._extends(String.class);
classDef._extends("XXClass");
classDef._implements("XXInterface1", "XXInterface2");
classDef.annotate("Controller");
生成函数声明
//public String <T extends Thread> foo(T param1, String[] param2, Object... params) throws Exception {}
public static final int VARARGS = 1 << 31; // JMod.VARARGS不是public的,不能访问
JMethodDef methodDef = classDef.method(JMod.PUBLIC, String.class, "foo");
methodDef.typeParam("T")._extends(Thread.class);
methodDef.param(JMod.FINAL, "T", "param1");
methodDef.param(0 , String[].class.getCanonicalName(), "param2");
methodDef.param(JMod.FINAL | VARARGS, Object.class, "params");
methodDef._throws(Exception.class);
生成属性
// private static final String DEFAULT_VALUE = "ONE";
classDef.field(JMod.PRIVATE | JMod.STATIC | JMod.FINAL, String.class, "DEFAUL_VALUE", JExprs.str("ONE"));
生成函数体
JBlock body = methodDef.body();
body.xxx
生成if语句
/**
if (var1 == null) {
var1 = "var1 value";
if (var1.startWith("var1")) {
System.out.println(var1);
return;
} else if (var1.startWith("var1")) {
var1 = "var2 value";
return;
}
}
**/
JIf if1 = body._if(JExprs.$v(var1).eq(JExpr.NULL));
if1.assign(JExprs.$v(var1), JExprs.str("var1 value"));
JIf if1_1 = if1._if(JExprs.$v(var1).call("startWith").arg(JExprs.str("var1")));
if1_1.call(JTypes.$t(System.class).$v("out"), "println").arg(JExprs.$v(var1));
if1_1._return();
JIf if2 = if1.elseIf(JExprs.$v(var1).call("startWith").arg(JExprs.str("var1")));
JBlock block = if1._else();
注意: if1可以调用elseIf也可以调用_esle, 但是不能两者都调用, 只能调用其中一个, 否则会报错(这里是否有改进的空间)
生成for语句
//foreach方式 for(String tmp : var1) var1需要可迭代
body.forEach(0, String.class, "tmp", JExprs.$v(var1));
//for形式 for (int tmp = 0; tmp <= 10; tmp++) {}
JFor for1 = body._for();
JVarDeclaration testVar = for1.init(0, int.class, "tmp", JExprs.decimal(0));
for1.test(JExprs.$v(testVar).le(JExprs.decimal(10)));
for1.update(JExprs.$v(testVar).postInc());
生成while语句
//java.sql.ResultSet resultSet = stmt.executeQuery("select * from xx");
//while (resultSet.next() == true) {}
JCall queryCall = JExprs.$v("stmt").call("executeQuery").arg(JExprs.str("select * from xx"));
JVarDeclaration resultSet = body.var(0, ResultSet.class, "resultSet", queryCall);
JBlock whileBlock = body._while(JExprs.$v(resultSet).call("next").eq(JExpr.TRUE));
//do {
// i++;
//} while (i<10);
JBlock doBlock = body._do(JExprs.$v("i<10"));
doBlock.add(JExprs.$v("i").postInc());
方法调用
//调用startWith函数, var1.startWith("var1")
JExprs.$v(var1).call("startWith").arg(JExprs.str("var1"))
生成注释
classDef.docComment().htmlTag("ul", true).attribute("class", "banana").htmlTag("li", false).text("A line item");
classDef.docComment().docTag("author", "Someone");
methodDef.blockComment().text("块注释");
var1.lineComment().text("行注释").nl();
较为完整的例子
代码如下;
import org.jboss.jdeparser.*;
import org.junit.Test;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.math.BigDecimal;
import java.sql.ResultSet;
public class SimpleExampleTestCase extends AbstractGeneratingTestCase {
public static final int VARARGS = 1 << 31;
@Test
public void testSimple() throws IOException {
final JSources sources = JDeparser.createSources(getFiler(), new FormatPreferences());
final JSourceFile bazFile = sources.createSourceFile("org.foo.bar", "Baz");
bazFile._import(BigDecimal.class);
final JClassDef classDef = bazFile._class(JMod.PUBLIC, "Baz");
classDef.docComment().htmlTag("ul", true).attribute("class", "banana").htmlTag("li", false).text("A line item");
classDef.docComment().docTag("author", "Someone");
classDef.typeParam("T")._extends(String.class);
classDef._extends("XXClass");
classDef._implements("XXInterface1", "XXInterface2");
classDef.annotate("Controller");
JVarDeclaration var = classDef.field(JMod.PRIVATE | JMod.STATIC | JMod.FINAL, String.class, "DEFAUL_VALUE", JExprs.str("ONE"));
//var.add("ddd", JExpr.NULL);
JMethodDef methodDef = classDef.method(JMod.PUBLIC, String.class, "foo");
methodDef.blockComment().text("块注释");
///methodDef.docComment().docTag("Date", "20190101");
methodDef.typeParam("T")._extends(String.class);
methodDef.param(JMod.FINAL , "T", "param1");
methodDef.param(0 , String[].class.getCanonicalName(), "param2");
methodDef.param(JMod.FINAL | VARARGS, Object.class, "params");
methodDef._throws(Exception.class);
JBlock body = methodDef.body();
JVarDeclaration var1 = body.var(0, String.class, "var1", JExpr.NULL);
var1.lineComment().text("行注释").nl();
JIf if1 = body._if(JExprs.$v(var1).eq(JExpr.NULL));
if1.assign(JExprs.$v(var1), JExprs.str("var1 value"));
JIf if1_1 = if1._if(JExprs.$v(var1).call("startWith").arg(JExprs.str("var1")));
if1_1.call(JTypes.$t(System.class).$v("out"), "println").arg(JExprs.$v(var1));
if1_1._return();
JIf if2 = if1.elseIf(JExprs.$v(var1).call("startWith").arg(JExprs.str("var1")));
if2.assign(JExprs.$v(var1), JExprs.str("var2 value"));
if2._return();
// JBlock block = if1._else();
// block.assign(JExprs.$v(var1), JExprs.str("var3 value"));
body.forEach(0, String.class, "tmp", JExprs.$v(var1));
JFor for1 = body._for();
JVarDeclaration testVar = for1.init(0, int.class, "tmp", JExprs.decimal(0));
for1.test(JExprs.$v(testVar).le(JExprs.decimal(10)));
for1.update(JExprs.$v(testVar).postInc());
JCall queryCall = JExprs.$v("stmt").call("executeQuery").arg(JExprs.str("select * from xx"));
JVarDeclaration resultSet = body.var(0, ResultSet.class, "resultSet", queryCall);
JBlock whileBlock = body._while(JExprs.$v(resultSet).call("next").eq(JExpr.TRUE));
JBlock doBlock = body._do(JExprs.$v("i<10"));
doBlock.add(JExprs.$v("i").postInc());
sources.writeSources();
final ByteArrayInputStream inputStream = openFile("org.foo.bar", "Baz.java");
final BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
}
}
输出结果如下;
package org.foo.bar;
import java.math.BigDecimal;
/**
* <ul class="banana">
* <li>A line item
* @author Someone
*/
@Controller
public class Baz<T extends String> extends XXClass implements XXInterface1, XXInterface2 {
private static final String DEFAUL_VALUE = "ONE";
/*
* 块注释
*/
public <T extends String> String foo(final T param1, String[] param2, final Object... params) throws Exception {
// 行注释
String var1 = null;
if (var1 == null) {
var1 = "var1 value";
if (var1.startWith("var1")) {
System.out.println(var1);
return;
}
} else if (var1.startWith("var1")) {
var1 = "var2 value";
return;
}
for (String tmp : var1) {}
for (int tmp = 0; tmp <= 10; tmp++) {}
java.sql.ResultSet resultSet = stmt.executeQuery("select * from xx");
while (resultSet.next() == true) {}
do {
i++;
} while (i<10);
}
}