クラスを操作してみる


では、実際に簡単なクラスを用意して操作をしてみることにしましょう。ここでは、以下のようなごくシンプルなBeanクラスを作成し、これを操作してみることにします。

package jp.tuyano.jasample;

public class TestBean {
 public String testfield = "helo";
 
 public void test(){
  System.out.println(testfield);
 }
}


これをコンパイルしクラスファイルを作成しておきます。このクラスファイルに、直接フィールドとクラスを追加してみることにしましょう。

package jp.tuyano.jasample;

import java.io.IOException;
import java.lang.reflect.*;

import javassist.*;

public class JavassistSample {

 public static void main(String[] args) {
  ClassPool pool = ClassPool.getDefault();

  try {
   CtClass cc = pool.get("jp.tuyano.jasample.TestBean");
   
   // フィールドの追加
   cc.addField(new CtField(CtClass.intType,"addfield",cc));
   
   // メソッドの追加
   String mstr = "public void addmethod(){System.out.println(""add this method."");}";
   cc.addMethod(CtMethod.make(mstr,cc));
   cc.writeFile();
  } catch (NotFoundException e) {
   e.printStackTrace();
  } catch (CannotCompileException e) {
   e.printStackTrace();
  } catch (IOException e) {
   e.printStackTrace();
  }
  printTestBean();
 }

 // TestBeanのクラスとフィールドを出力する
 public static void printTestBean(){
  Class c = TestBean.class;
  System.out.println("[class]");
  System.out.println(c.getName());
  
  Method[] methods = c.getMethods();
  System.out.println("[methods]");
  for(Method m:methods){
   System.out.println(m.getName());
  }
  
  Field[] fields = c.getFields();
  System.out.println("[fields]");
  for(Field f:fields){
   System.out.println(f.getName());
  }
 }

}


これを実行すると、TestBeanのクラスファイルを書き換えて「addmethod」というメソッドと「testfield」というフィールドを追加します。追加後にTestBean内のメソッドとフィールド名を書き出していますので、ここで確認をしてみてください。これらのフィールドとメソッドが追加されているはずです。

実行するとコンソールにTestBeanクラス内のメソッドとフィールドが書き出される。


では、簡単な流れを説明しておきましょう。実際に操作を行なっているのはmainメソッドの部分になります。

ClassPool pool = ClassPool.getDefault();


まず、ClassPoolを取得します。これは、ClassPool.getDefaultでデフォルトのClassPoolが得られますので、通常はこれを使います。

CtClass cc = pool.get("jp.tuyano.jasample.TestBean");


続いて、TestBeanのCtClassを取得します。これはClassPoolのgetメソッドを使います。ここで取り出すクラス名を引数として渡せば、そのクラスのCtClassインスタンスが得られます。このとき、完全修飾名でクラスを指定するようにしておきましょう。

cc.addField(new CtField(CtClass.intType,"addfield",cc));


CtClassが得られたら、クラスを修正に進みます。最初にフィールドを追加します。フィールドは、CtFieldインスタンスとして扱われます。これは、new CtFieldとして作成します。引数には、フィールドの種類を示す値(CtClass内のクラスフィールドを使って指定します)、フィールド名、組み込み先のCtClassをそれぞれ渡します。

String mstr = "public void addmethod(){System.out.println(""add this method."");}";
cc.addMethod(CtMethod.make(mstr,cc));


続いてメソッドの作成です。メソッドは、あらかじめメソッドの内容をStringとして用意しておきます。そして、CtMethodのmakeメソッドで追加をします。引数には、メソッドの内容を示すStringと組み込み先のCtClassを渡します。

cc.writeFile();


修正が終わったら、最後にCtClassのwriteFileを呼び出してクラスファイルを書き換えます。これで修正した状態にクラスファイルが変更されます。