當大量代碼遵循固定模式(如 Entity → DAO/Service/Controller、DTO ↔ VO 轉換、Builder 模式)時,手工編寫不僅低效且易出錯。CodeModel 作為 JAXB 子項目,提供**程序化構建 Java 語法樹**的能力,輸出可編譯、可維護的 .java 文件,優於字符串拼接或模板引擎的類型安全與重構友好性。
| 類 | 職責 |
|---|---|
| JCodeModel | 根容器,管理包/類/導入,最終 build(File) 落盤 |
| JDefinedClass | 類/接口/枚舉定義,含字段/方法/構造器/註解創建 |
| JMethod / JConstructor | 方法/構造器定義,body() 返回 JBlock |
| JBlock | 方法體,提供變量聲明、控制流、調用、賦值、返回等語句構建 |
| JExpr | 表達式工廠:字面量、引用、新建、轉型、二元運算、方法調用鏈 |
| JVar / JFieldVar | 局部變量 / 成員字段 |
| JType / JClass | 類型引用,parseType("pkg.Type") 解析引用類型 |
// 基本類型
JVar i = block.decl(cm.INT, "i", JExpr.lit(0));
// 引用類型
JType listType = cm.parseType("java.util.List<String>");
JVar list = block.decl(listType, "list", JExpr._new(cm.parseType("ArrayList")));
// 靜態常量
dc.field(JMod.PUBLIC | JMod.STATIC | JMod.FINAL, cm.INT, "MAX", JExpr.lit(100));
// if-else
JConditional iff = block._if(JExpr.ref("a").gt(JExpr.ref("b")));
iff._then().invoke("doA");
iff._else().invoke("doB");
// for 循環
JForLoop loop = block._for();
loop.init(cm.INT, "i", JExpr.lit(0));
loop.test(JExpr.ref("i").lt(JExpr.lit(10)));
loop.update(JExpr.ref("i").incr());
loop.body().invoke("process").arg(JExpr.ref("i"));
// 實體類
JDefinedClass clazz = cm._class("com.example.User");
// 抽象類
JDefinedClass abs = cm._class(JMod.PUBLIC | JMod.ABSTRACT, "com.example.Base", ClassType.CLASS);
// 接口
JDefinedClass iface = cm._class(JMod.PUBLIC, "com.example.Service", ClassType.INTERFACE);
// 繼承與實現
sub._extends(abs);
impl._implements(iface);
clazz.javadoc().add("用戶實體類").addParam("id", "主鍵");
method.annotate(Override.class);
輸入:包名、類名。輸出:Singleton.java(雙重檢查鎖/靜態內部類任選)+ SingletonTest.java。
public class SingletonGen {
public void gen() throws Exception {
JCodeModel cm = new JCodeModel();
JDefinedClass dc = cm._class("demo.Singleton");
JType t = cm.parseType("demo.Singleton");
// 私有構造器
dc.constructor(JMod.PRIVATE);
// 靜態實例字段
dc.field(JMod.PRIVATE | JMod.STATIC | JMod.VOLATILE, t, "INSTANCE");
// getInstance() 方法
JMethod get = dc.method(JMod.PUBLIC | JMod.STATIC, t, "getInstance");
JBlock body = get.body();
JConditional c = body._if(JExpr.ref("INSTANCE").eq(JExpr._null()));
JBlock sync = c._then()._synchronized(JExpr.ref("INSTANCE"));
JConditional c2 = sync._if(JExpr.ref("INSTANCE").eq(JExpr._null()));
c2._then().assign(JExpr.ref("INSTANCE"), JExpr._new(t));
body._return(JExpr.ref("INSTANCE"));
cm.build(new File("src"));
}
}
生成代碼符合標準雙重檢查鎖單例,可直接編譯運行。
cm.parseType() 而非字符串拼接類型