程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> 用 Java 生成 Java:CodeModel 介紹

用 Java 生成 Java:CodeModel 介紹

編輯:關於JAVA

在我們編寫代碼的時候,常常會有這樣的情形:一部分代碼是可以根據另一部分代碼按照某種特定的模式變化而來的; 有時,隨著那一部分被依賴的代碼發生變化,依賴的代碼不得不跟著修改;有時,這樣的代碼會隨著項目的推進,不止一次 的出現。很典型的一個例子就是,當需要自己實現數據訪問層時,通常每個實體類會對應一個 DAO(數據訪問對象)類,並 且一般來講 DAO 類的代碼編寫是很機械的。這時,我們就需要使用“代碼生成”來提高我們的開發效率以及提高代碼的可 維護性。

Java 有很多種方法可以實現“代碼生成”,比如,直接使用打印語句或者使用模板引擎。但相比較而言, 使用 CodeModel 會使代碼更靈活也更容易維護。CodeModel 的官網除了 Javadoc 沒有提供很好的學習文檔,所以我們在項 目中使用時也是不斷地摸索。因此,本文既是一篇 CodeModel 的介紹文章,也是我們對 CodeModel 使用的經驗總結。本文 將按照一般的學習編程語言的思路並結合示例代碼向讀者朋友們介紹 CodelModel 的使用方法。希望能對讀者朋友們有所幫 助。

CodeModel 簡介

CodeModel 是用於生成 Java 代碼的 Java 庫,它提供了一種通過 Java 程序來生成 Java 程序的方法。

CodeModel 項目是 JAXB 的子項目。JAXB(Java Architecture for XML Binding)是一項可以 根據 XML Schema 產生 Java 類的技術,它提供了將 XML 實例文檔反向生成 Java 對象樹的方法,並能將 Java 對象樹的 內容重新寫到 XML 實例文檔。JAXB 是 JDK 的組成部分。JAXB RI(Reference Implementation)即 schema compiler 能 夠將 XML 的 schema 文件映射為相應的 Java 元素。

CodeModel 的使用方法

如果去閱讀 JCodeModel 的 API 文檔,JCodeModel 類是我們第一個要去接觸的。JCodeModel 類是生成 Java 代碼的根。通常我們按照自上而下的順序 生成所需要的 Java 代碼。比如首先創建一個類 JDefinedClass,然後再通過類生成方法、方法體以及方法體內的代碼…… 依次而下。

一個 CodeModel 的典型應用如下:

清單 1. CodeModel 的典型應用

JCodeModel 

cm = new JCodeModel(); 
// 通過構建 cm 樹來生成 Java 代碼
cm._class(...); 
... 
// 自上而下地生成類、方法等
cm.build(new File("."));

在 CodeModel 中除了 JCodeModel 類,幾個常用的類有 JDefinedClass、JMethod、 JBlock、JFieldVar、JVar、JType、JExpr 等。

JDefinedClass 類是 CodeModel 來定義類的,它提供了類自身的 創建、繼承、實現,以及類成員變量、成員方法的創建方法等

JMethod 類是 Java 的方法類,它可以創建方法體, 那麼就有了 JBlock 類

JBlock 類是我們經常要用到的類,它提供了非常多的方法:局部變量的聲明、變量賦值、 生成各種控制語句、調用其他方法、設置方法的返回值等

JFieldVar 類用來定義類的成員變量,它可以對成員變量 進行聲明、賦值等

JVar 類用來定義變量,提供了變量的基本操作如聲明、賦值、初始化等

JType 類用來 定義 Java 中的各種數據類型

JExpr 類表達式的工廠類,它提供了 TRUE 和 FALSE 兩個常量值,以及生成表達式 的各種方法以及表達式的賦值等

為了方便後面的代碼演示,現在這裡構建好 cm 樹和 dc 類,CodeModel 會在當前 項目的 src 文件夾 -> dw 包下生成名為 example 的 Java 類。

清單 2. 構建 cm 樹和 dc 類

File destDir = new File ((new File("src")); 
JCodeModel cm = new JCodeModel();// 實例化 CodeModel 
JDefinedClass dc = cm._class("dw.example"); // 創建 example 類

變量聲明與賦值

變量類型

Java 的變量類型包括基本數據類型和引用數據類型。

JCodeModel 類中定義了幾個常量來映射 Java 的基本 數據類型。

JCodeModel 的成員常量 BOOLEAN、BYTE、CHAR、SHORT、INT、LONG、FLOAT 和 DOUBLE 涵蓋了 Java 所 有的基本數據類型(boolean、byte、char、short、int、long、float、double),以及 NULL、VOID 等。可以通過 cm 直 接得到。

關於引用類型,可以通過 JCodeModel 類的 parseType 方法來得到。在 parseType 方法的參數中指定要 引用的類型,通過類型名來獲取對象。

清單 3. 獲取引用變量類型

JType type = cm.parseType

("String"); 
JType type1 = cm.parseType("myType");

之後便可以使用 type、type1 來定義變量的類型。

本地變量和 成員變量

Java 的變量可以分為本地變量(也成為局部變量)和成員變量(也成為實例變量)。

對於本地變 量,可以使用 JBlock 類中的 decl 方法對本地變量進行定義和初始化。本地變量是 JVar 類型。JBlock 類提供了三個重 載的 decl 方法,分別是:

decl(int mods, JType type, String name, JExpression init)

decl(JType type, String name)

decl(JType type, String name, JExpression init)

上面的方法通過 int mods 來定 義變量的修飾符,mods 來自 CodeModel 的 JMod 類。JMod 類定義了一些 Java 的修飾符常量,包括 ABSTRACT、FINAL、 PRIVATE、PROTECTED、PUBLIC、STATIC、SYNCHRONIZED 等。如果要使用多個修飾符,可以通過“+”來實現;

通過 type 來定義變量的類型;通過 name 來定義變量的名字;通過 init 來定義變量的初始值。

清單 4. 生成 Java 本地變量

JMethod exampleMethod = dc.method(JMod.PUBLIC, cm.VOID, "exampleMethod"); 
JBlock exampleMethodBlk = exampleMethod.body(); 
JVar var = exampleMethodBlk.decl(type, "fieldVar"); 
JVar var1 = exampleMethodBlk.decl(type, "fieldVar1",JExpr.lit(5));

以上代碼創建了名為 exampleMethod 的方法,並創建了該方法的方法體 exampleMethodBlk,通過方法體的 decl 方法創建了這個方法的變量 var 和 var1,並 給變量 var1 賦了初始值。

代碼的運行結果為:

public void exampleMethod() { 
   int fieldVar; 
   int fieldVar1 = 5; 
}

對於 Java 的成員變量,可以通過 JDefinedClass 類的 field 方法來生成。成員變量是 JFieldVar 類型的。 JDefinedClass 類提供了四個重載的 field 方法來生成成員變量如下,通過 mods 來定義成員變量的修飾符;通過 type 來定義變量的類型;通過 name 來定義變量的名字;通過 init 來定義變量的初始值。

field(int mods, Class<?> type, String name)

field(int mods, Class<?> type, String name, JExpression init)

field(int mods, JType type, String name)

field(int mods, JType type, String name, JExpression init)

清單 5. 生成 Java 成員變量

JFieldVar fVar = dc.field(JMod.PUBLIC, 

cm.INT, "a"); 
JFieldVar fVar1 = dc.field(JMod.PRIVATE, cm.parseType("String"), "b", JExpr.lit(“abc”));

代碼的運 行結果為:

public class example {
    public static a;
    private String b = “abc”;
}

靜態變量和常量

要定義靜態變量,只需要在生成變量方法的修飾符 處定義 static 即可。和靜態變量類似的,常量則需要在修飾符處定義 final。

清單 6. 生成靜態變量和常量

dc.field(JMod.PRIVATE + JMod.STATIC, cm.parseType("String"), 
         "staticVar", JExpr.lit("abc")); 
dc.field(JMod.PUBLIC + JMod.FINAL, cm.INT, "MAX_ARRAY_SIZE",JExpr.lit(25));

以上代碼的運行結果為:

private static String staticVar= "abc";
public final int MAX_ARRAY_SIZE = 25;

變量賦值

CodeModel 庫中的 JExpr 類提供了生成表達式(JExpression 類型)的各種方法。JExpr 類的 lit 方法可以生成 Java 基本數據類型的表達式,作為變量初始化的值。

lit(boolean b) // 布爾類型
lit(char c) // 字符型
lit(int n) // 整型
lit(long n) // 長整型
lit(double d) // 雙精度 浮點型
lit(float f) // 單精度浮點型
lit(String s) // 字符串類型

在本文前面的示例代碼 中,都有對變量的定義和賦值,但基本上是針對 Java 的基本數據類型,那麼對於引用數據類型,CodeModel 是如何使用的 呢?

對於數組類型,只需要將要定義的數組類型通過 parseType 獲取到,通過 JExpr 的 newArray 方法生成數組 類型變量,使用 CodeModel 的數組類 JArray 的 add 方法來進行數組變量的初始化。JExpr 類提供了三個重載的 newArray 方法如下,分別可以定義數組的類型 type、數組的長度 size。

   newArray(JType type)
   newArray(JType type, int size)
   newArray(JType type, JExpression size)

清單 7. 數組變量的生成與賦值

JType arrType = cm.parseType("int []"); // 定義數組類

型
JArray initArray = JExpr.newArray(cm.INT); // 創建類型為整型的數組
dc.field(JMod.PUBLIC, arrType, "arr", initArray); 
initArray.add(JExpr.lit(0)); 
initArray.add(JExpr.lit(1));

運行結果為:

public class example {
   public int[] arr = new int[ ] { 0, 1 };
}

關於 Java 其他引用類型 - 類和接口的定義和使用,後面會 詳細介紹。

變量的強制類型轉換

CodeModel JVar 類的 cast 方法可以實現變量間的強制類型轉換。在 cast 的參數中執行要轉換的類型(JType type)和需要轉換的變量表達式(JExpression expr)即可。

清單 8. 變量的 強制類型轉換

JVar longValue = exampleMethodBlk.decl(cm.LONG, "longValue",JExpr.lit(99L)); 
JVar intValue = exampleMethodBlk.decl(cm.INT, "intValue", 
JExpr.cast(cm.INT, JExpr.ref("longValue")));

運行結果如下:

long longValue = 99L;
int intValue = ((int) longValue)

類和接口

實體類和抽象類

在 CodeModel 的 JCodeModel 類 和 JDefinedClass 類中都提供了生成類的方法 _class。

可以使用 JCodeModel 類中的 _class 方法來生成 Java 實體類或抽象類。JCodeModel 類提供了三個重載的 _class 方法來生成類。通過 mods 來指定類的修飾符,通過 fullyqualifiedName 來指定類的完全限定名,通過 t 來指定類的類型。如果要生成抽象類,則可以指定類的修飾符為 ABSTRACT。

   _class(int mods, String fullyqualifiedName, ClassType t)
   _class(String fullyqualifiedName)
   _class(String fullyqualifiedName, ClassType t)

在 JDefinedClass 類中有四個生成類的方法 _class 如下,用來在一個類中生成嵌套的類。對於方法中的參數,可 以通過 mods 來指定類的修飾符,name 來指定類的名字,classTypeVal 來指定類的類型,isInterface 來指定是否為接口 。

   _class(int mods, String name)
   _class(int mods, String name, boolean isInterface)
   _class(int mods, String name, ClassType classTypeVal)
   _class(String name)

清單 9. 生成類

JDefinedClass exampleClass = cm._class

("dw.examples.exampleClass"); 
exampleClass.method(JMod.PUBLIC, cm.VOID, "methodA").body().invoke("dosomething");

代碼運行結果如下 ,生成了實體類 exampleClass:

public class exampleClass {
   public void methodA() {
       dosomething();
   }
}

Java 的抽象類不 能直接使用,必須用子類去實現抽象類,然後使用其子類的實例。下面的代碼演示如果通過子類實現抽象類。

清單 10. 通過子類實現抽象類

// 生成抽象類
JDefinedClass abstractClass = cm._class(JMod.PUBLIC + JMod.ABSTRACT, 
                              "dw.examples.abstractClass", ClassType.CLASS); 
abstractClass.method(JMod.PUBLIC + JMod.ABSTRACT, cm.VOID, "methodB");

代碼運行結果如下,生成了抽象 類 abstractClass:

public abstract class abstractClass {
    public abstract void methodB();
}

// 子類實現抽象類
JDefinedClass sonClass = cm._class (JMod.PUBLIC,"dw.examples.sonClass",ClassType.CLASS);
sonClass._extends(abstractClass);
sonClass.method(JMod.PUBLIC, cm.VOID, "methodB").body().invoke("dosomething");

代碼運行結果為:

public class generatedSonClass extends generatedAbstractClass
{
   public void methodB() {
       dosomething();
   }
}

接口

接口的生成和類相似,可以通過 JCodeModel 的 _class 方法來生成。需要 在 _class 方法的參數中指定類型為接口。在 ClassType 類中定義了幾個常量類型,包括 CLASS、INTERFACE、ENUM 等。 因此設定 _class 方法的參數 t 為 ClassType.INTERFACE 就可以了。

也可以使用 JDefinedClass 類中的 _class 方法,通過指定 isInterface 為 true 來在類中生成嵌套的接口。

清單 11. 生成接口

JDefinedClass 

exampleInterface = cm._class(JMod.PUBLIC, 
    "dw.examples.Runner", ClassType.INTERFACE); 
exampleInterface.field(0, cm.INT, "ID", JExpr.lit(1)); 
exampleInterface.method(JMod.PUBLIC, cm.VOID, "start"); 
exampleInterface.method(JMod.PUBLIC, cm.VOID, "run"); 
exampleInterface.method(JMod.PUBLIC, cm.VOID, "stop");

代碼運行結果為:

public interface Runner {

   int ID = 1;
   public void start();
   public void run();
   public void stop();

}

接口需要通過類來實現 ,以下代碼演示如何通過類來實現接口。

清單 12. 通過類實現接口

JDefinedClass impClass = 

cm._class(JMod.PUBLIC,"dw.examples.Person",ClassType.CLASS); 
impClass._implements(exampleInterface); 
impClass.method(JMod.PUBLIC, cm.VOID, "start").body().invoke("actions"); 
impClass.method(JMod.PUBLIC, cm.VOID, "run").body().invoke("actions"); 
impClass.method(JMod.PUBLIC, cm.VOID, "stop").body().invoke("actions");

生成的代碼如下:

public class Person
   implements Runner
{
   public void start() {
       actions();
   }

   public void run() {
       actions();
   }

   public void stop() {
       actions();
   }
}

類的調用

對於 Java 的基本類,可以通過 JCodeModel 類的 ref 方法來實現。JCodeModel 類提供了兩個重載的 ref 方法,可以通過類對 象和類的完全限定名來調用。

ref(Class<?> clazz)
ref(String fullyQualifiedClassName)

清單 13. 基本類的調用

JBlock body = exampleMethod.body(); 
JClass sys = cm.ref("java.lang.System"); 
body.invoke(sys.staticRef(“out”),”println”).arg(“HelloWorld!”);

而對於自定義類的引用,則可以通 過 JExpr 類的 _new 方法來實例化,通過 JBlock 類的 assign 方法可以實現賦值。JExpr 類提供了兩個 _new 方法來實 現類的使用。通過方法 _new(JClass c) 和 _new(JType t) 的參數可以指定生成對象的類型。

清單 14. 自定義類 的調用

// 生成 myDate 類,它有 day、month、year 三個變量
dc.field(0, cm.INT, "day"); 
dc.field(0, cm.INT, "month"); 
dc.field(0, cm.INT, "year"); 
            
JType classType = cm.parseType("myDate"); // 定義類的類型
JMethod newMyDate = dc.method(JMod.PUBLIC, cm.VOID, "newMyDate"); // 創建公共方法 newMyDate 
JBlock blk = newMyDate.body(); 
JVar today = blk.decl(classType, "today"); // 定義變量
blk.assign(today, JExpr._new(classType)); // 創建新的類對象並將它賦給 today

生成的代碼如下:

public class myDate {

   int day;
   int month;
   int year;

   public void newMyDate() {
       myDate today;
       today = new myDate();
   }
}

方法

方法 的定義

對於 Java 類的構造方法,需要使用 JDefinedClass 類的 constructor 方法來生成,而對於類的成員方法 ,則可以通過 JDefinedClass 類的 method 方法來定義和生成。JDefinedClass 有兩個重載的 method 方法。可以定義方 法的修飾符 mods、返回值類型 type 以及方法名 name。如果方法是抽象的,則需設定 mods 為 ABSTRACT。

   method(int mods, Class<?> type, String name)
   method(int mods, JType type, String name)

清單 15. 構造方法和成員方法的生成

dc.constructor(JMod.PUBLIC); 
dc.method(JMod.PUBLIC, methodType, "exampleMethod");

第一行代碼就生成了類的公共的構造方法。第二行代 碼則通過 method 方法生成了類的一個公共的成員方法 exampleMethod。

方法的調用

方法的調用是通過 JBlock 類的 invoke 方法來實現的。JBlock 類提供了四個 invoke 方法,可以設定方法的調用者 expr,也可以不指定調 用者直接通過方法名 method 使用。

   invoke(JExpression expr, JMethod method)
   invoke(JExpression expr, String method)
   invoke(JMethod method)
   invoke(String method)

清單 16. 方法的調用

exampleBlk.invoke (JExpr.ref("expA"), "methodB").arg("argA");

運行結果如下:

expA.methodB(“argA”);

控制語句

條件語句(if,switch)

Java 支持雙路 if 和多路 switch 分支語句。

在 CodeModel 中,使用 JBlock 類中的 _if 方法來生成 if 控制語句,方法 _if(JExpression expr) 的參數中可以指定 if() 的布爾表達式。而 else 塊是通過 if 塊(JConditional 類)的方法 _else 來生成的, else 部分是選擇性的。JConditional 類還提供了 _elseif 方法來創建 else if ( … ) 語句。

清單 17. if 語句 代碼演示

JConditional outerIf = exampleBlk._if(JExpr.ref("a1").gt(JExpr.ref("a2"))); 
JBlock outerThen = outerIf._then(); 
JBlock outerElse = outerIf._else(); 
JConditional innerIf = outerThen._if(JExpr.ref("a1").gt(JExpr.ref("a3"))); 
JBlock innerThen = innerIf._then(); 
JBlock innerElse = innerIf._else();

生成的代碼如下:

if (a1 >a2) {
   if (a1 >a3) {
   } else {
   }
} else {
}

Java 中的 switch 語句,是通過 JBlock 類的 _switch 方法來生成的。而 switch 中的 case 語句,則是通過 JSwitch 類的 _case 方法生成的。要生成某個 case 代碼段,就需要使用 JCase 類的 body 方法來生成方法體,然後在該方法體內增加 其他代碼。

清單 18. switch 語句代碼演示

exampleBlk.decl(cm.INT, "colorNum", JExpr.lit(0)); 
JSwitch exampleSwitch = exampleBlk._switch(JExpr.ref("colorNum")); 
JCase caseA = exampleSwitch._case(JExpr.lit(0)); 
caseA.body().invoke("caseA"); 
JCase caseB = exampleSwitch._case(JExpr.lit(1)); 
JBlock caseBBody = caseB.body(); 
caseBBody.invoke("caseB"); 
caseBBody._break(); 
JCase caseC = exampleSwitch._case(JExpr.lit(2)); 
caseC.body()._break();

生成的代碼如下:

int colorNum = 0;
switch (colorNum) {
   case  0 :
       caseA();
   case  1 :
       caseB();
       break;
   case  2 :
       break;
}

循環語句(for,while,do … while)

Java 支持三種循環構造類型:for、while 和 do。

對於 for 循環,使用 CodeModel JBlock 類的 _for 方 法來生成一個 for 語句。

for 語句的初始表達式則需要 JForLoop 類的 init 方法來生成,JForLoop 類提供了三 個重載的 init 方法,可以指定變量的修飾符(int mods)、類型(JType type)、名字(String var)以及初始值 (JExpression e)。

   init(int mods, JType type, String var, JExpression e)
   init(JType type, String var, JExpression e)
   init(JVar v, JExpression e)

for 語句的測試表達式是由 JForLoop 類的 test 方法生成的,test 方法通過 JExpression e 指定測試表達式。

test (JExpression e)

for 語句的改變量表達式是由 JForLoop 類的 update 方法生成的,update 方法通過 JExpression e 指定改變變量表達式。

update(JExpression e)

清單 19. for 語句代碼演示

JForLoop exampleFor = exampleBlk._for(); 
exampleFor.init(cm.INT,"i", JExpr.lit(0)); 
exampleFor.test(JExpr.ref("i").lt(JExpr.lit(10))); 
exampleFor.update(JExpr.ref("i").incr()); 
JBlock forBody = exampleFor.body(); 
forBody.invoke("dosomething");

運行結果如下:

for (int i = 0; (i< 10); i ++) {
   dosomething();
}

Java 的 while 循環是通過 CodeModel JBlock 類的 _while 方法 生成的,通過 _while 方法的參數 JExpression test 來定義 while 循環的表達式。

_while(JExpression test)

清單 20. while 語句代碼演示

JVar i = exampleBlk.decl(cm.INT, "i", JExpr.lit(0)); 
JWhileLoop exampleWhile = exampleBlk._while(JExpr.ref("i").lt( 
JExpr.lit(10))); 
JBlock whileBody = exampleWhile.body(); 
whileBody.invoke("dosomething"); 
whileBody.assignPlus(i, JExpr.lit(1));

運行結果為:

int i = 0;
while (i< 10) {
   dosomething();
   i += 1;
}

Java 的 do 循環是通過 CodeModel JBlock 類的 _do 方法生成的,通過 _do 方法的 JExpression test 來定義 do while 循環的表達式。

_do(JExpression test)

清單 21. do … while 語句代碼演示

JVar i = 

exampleBlk.decl(cm.INT, "i", JExpr.lit(0)); 
JDoLoop exampleDo = exampleBlk._do(JExpr.ref("i").lt(JExpr.lit(10))); 
JBlock doBody = exampleDo.body(); 
doBody.invoke("dosomething"); 
doBody.assignPlus(i, JExpr.lit(1));

運行結果為:

int i = 0;
do {
   dosomething();
   i += 1;
} while (i< 10);

轉移語句(break, continue)

Java 中的 break 和 continue 用於特殊循環流程控制,可以通過 CodeModel JBlock 類中的 _break 和 _continue 來生成。此處不再詳述。

注釋與 Javadoc

注釋與 Javadoc 也是 Java 程序中不可或缺的部分 。使用 CodeModel JDefinedClass 類中的 javadoc 方法或 Jmethod 類中的 javadoc 方法可以用來生成類級或方法級的 Javadoc。

方法 javadoc 的返回類型為 JDocComment 類型。該 JDocComment 類的方法 addParam 可以生成 @param 標簽,addReturn 生成 @return 標簽,addThrows 生成 @throws 標簽,addXdoclet 生成特殊的注釋信息等。JDocComment 類的 add 方法可以生成 Javadoc 的內容。後面的實例分析會有關於生成注釋和 Javadoc 的代碼,在此不再做代碼演示。

實例分析:使用 CodeModel 實現一個單例生成器

如何實現單例類生成器

我們來分析一下:要實現一 個單例生成器,需要首先創建一個 Singleton 類,在該類中定義一個靜態成員變量 instance。我們可以用代碼生成該類的 構造函數 Singleton()。Singleton 類還必須有一個靜態的公共的方法來獲取到實例,我們將其命名為 getInstance(),此 外,我們給 Singleton 類創建一個名為 sayHello() 的成員方法,讓其打印出傳入的參數。

為了測試我們的 Singleton 類,我們再讓程序生成另外一個類 singletonTest,這個類將通過 Singleton 類的 getInstance() 方法得到一 個單例實例,再調用 sayHello() 方法打印出“Hello CodeModel!”。

有了以上的分析,結合之前介紹的 CodeModel 生成類、變量、方法以及控制語句的方法,代碼就很容易寫出來的。

代碼詳解

清單 22. 代碼 SingletonGen 來實現單例生成器

package dw; 
     
 import java.io.File; 
 import com.sun.codemodel.JBlock; 
 import com.sun.codemodel.JClass; 
 import com.sun.codemodel.JCodeModel; 
 import com.sun.codemodel.JDefinedClass; 
 import com.sun.codemodel.JConditional; 
 import com.sun.codemodel.JDocComment; 
 import com.sun.codemodel.JExpr; 
 import com.sun.codemodel.JExpression; 
 import com.sun.codemodel.JFieldRef; 
 import com.sun.codemodel.JInvocation; 
 import com.sun.codemodel.JMethod; 
 import com.sun.codemodel.JMod; 
 import com.sun.codemodel.JType; 
     
 /** 
 * This class will generate a singleton class "Singleton.java" and a test class 
 * "SingletonTest.java" under the specified package. 
 * 
 * @author Sonia ([email protected]) 
 * 
 */
 public class SingletonGen { 
     public void genSingleton() throws Exception { 
         JCodeModel cm = new JCodeModel(); 
         JType type = cm.parseType("Singleton"); 
         File destDir = new File("src"); 
         JDefinedClass dc = cm._class("dw.sample.Singleton"); 
         // 定義靜態成員變量
         dc.field(JMod.PRIVATE+ JMod.STATIC, type, "instance"); 
         // 定義單例類 Singleton 的構造函數
         dc.constructor(JMod.PRIVATE); 
     
         // 生成 Singleton 類的成員方法 getInstanceMethod 
         JMethod getInstanceMethod = dc.method(JMod.PUBLIC+ JMod.STATIC, type, 
"getInstance"); 
         JBlock getInstanceBody = getInstanceMethod.body(); 
         JFieldRef fieldRef = JExpr.ref("instance"); 
         JConditional conditionIf = getInstanceBody._if(fieldRef.eq(JExpr 
 ._null())); 
         JBlock thenPart = conditionIf._then(); 
         thenPart.assign(fieldRef, JExpr._new(type)); 
         getInstanceBody._return(fieldRef); 
         // 生成 Singleton 類的成員方法 sayHelloMethod 
         JMethod sayHelloMethod = dc.method(JMod.PUBLIC, cm.parseType("void"), 
"sayHello"); 
         // 生成方法級的 javadoc 
         sayHelloMethod.javadoc().add("This method will say Hello to the name.");   
         JBlock sayHelloBody = sayHelloMethod.body(); 
         sayHelloMethod.param(cm.parseType("String"), "name"); 
         JClass sys = cm.ref("java.lang.System"); 
         JFieldRef ot = sys.staticRef("out"); 
         JExpression sentance1 = JExpr.lit("Hello ").invoke("concat").arg( 
         JExpr.ref("name")); 
         JExpression sentance2 = sentance1.invoke("concat").arg("!"); 
         sayHelloBody.invoke(ot, "println").arg(sentance2);         
         cm.build(destDir); 
     } 
          
     public void genTest() throws Exception { 
         JCodeModel cm = new JCodeModel(); 
         File destDir = new File("src"); 
         JDefinedClass dc = cm._class("dw.sample.singletonTest");   
         // 生成類級的 javadoc 
         JDocComment jdoc = dc.javadoc(); 
         jdoc.add("This is the class to test the Singleton class."); 
         jdoc.addXdoclet("author Sonia ([email protected])"); 
         // 生成 main 方法
         JMethod mainMethod = dc.method(JMod.PUBLIC+ JMod.STATIC, 
         cm.parseType("void"), "main"); 
         JBlock mainBody = mainMethod.body(); 
         mainMethod.param(cm.parseType("String[]"), "args"); 
         JClass singleton = cm.ref("Singleton"); 
         JInvocation getIns = singleton.staticInvoke("getInstance"); 
         mainBody.invoke(getIns, "sayHello").arg(JExpr.lit("CodeModel")); 
         cm.build(destDir); 
     } 
         
     public static void main(String args[]) { 
         SingletonGen sg = new SingletonGen(); 
         try{ 
                 sg.genSingleton(); 
                 sg.genTest(); 
         } catch(Exception e) { 
                 e.printStackTrace(); 
         } 
     } 
 }

運行上述代碼將獲得兩個類 – Singleton 類和 singletonTest 類。

清單 23. 生成的 Singleton 類

package dw.sample; 
    public class Singleton { 
        private static Singleton instance; 
        private Singleton() { } 
        public static Singleton getInstance() { 
            if(instance== null) { 
               instance= new Singleton(); 
            } 
            return instance; 
        } 
    /** 
    * This method will say Hello to the name. 
    * 
    */
    public void sayHello(String name) { 
       System.out.println("Hello ".concat(name).concat("!")); 
    } 
}

清單 24. 生成的 singletonTest 類

package dw.sample; 
/** 
* This is the class to test the Singleton class. 
* 
* @author Sonia ([email protected]) 
*/
public class SingletonTest { 
    public static void main(String[] args) { 
       Singleton.getInstance().sayHello("CodeModel"); 
    } 
}

運行 singletonTest 類得到的結果是:

Hello CodeModel!

結束語

本文像讀者介紹了使用 Java 的 CodeModel 庫來生成 Java 代碼的方法,並提供了 Java 示例代碼向讀者進行演示,希望讀者能夠了解 CodeModel 的特性並應用於日常工作。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved