Javaプログラミング/Javaプログラミング関連情報

クラスファイルを強制変換する(4ページ目)

Javassistで、クラスファイル変換を使ってクラスの中身を変えてしまいましょう。

執筆者:掌田 津耶乃

Beanのアクセサを自動生成する


では、このJavassistの機能を利用して、もっと具体的な処理を考えてみましょう。一つの例として、「JavaBeansのBeanクラスにアクセサを自動生成する」というものはどうでしょうか。

Beanクラスでは、通常、属性などの値をprivateフィールドとして用意しておき、それにアクセスするためのGetter/Setterといったアクセサをメソッドとして用意します。これは、自分で手書きでソースコードを書くのはちょっと面倒ですよね。そこで、自動生成するような処理を考えてみましょう。

ここでは、クラスにpublicフィールドを用意しておくと、それを元にアクセサの処理をさせます。以下のような形でBeanクラスを処理すればよいでしょう。

1.クラスに用意されているpublicフィールドをすべて取得する。
2.フィールドの名前とタイプを調べ、それにアクセスするためのGetter/Setterメソッドを追加する。
3.フィールドをprivateに変更する。

では、実際に処理のためのクラスを定義しましょう。ここでは、「BeanAlter」というクラスを作成し、その中に「addAccesor」というメソッドとして処理を用意することにしましょう。

※BeanAlter.javaのソースコード

package jp.tuyano.jasample;

import java.lang.reflect.*;

import javassist.*;
import javassist.Modifier;

public class BeanAlter {
  
 public static boolean addAccesor(String s){
  ClassPool pool = ClassPool.getDefault();
  CtClass cc = null;
  boolean result = false;
  try {
   cc = pool.get(s);
   
   CtField[] flds = cc.getFields();
   for(CtField fld: flds){
    String fldname = fld.getName();
    String fldtype = fld.getType().getName();
    String getter = getGetter(fldname,fldtype,cc);
    String setter = getSetter(fldname,fldtype,cc);
    System.out.println("getter:" + getter);
    System.out.println("setter:" + setter);
    if (getter != null){
     cc.addMethod(CtNewMethod.make(getter,cc));
     CtField field = new CtField(fld.getType(),fldname, cc);
     field.setModifiers(Modifier.PRIVATE);
     cc.removeField(fld);
     cc.addField(field);
    }
    if (setter != null){
     cc.addMethod(CtNewMethod.make(setter,cc));
    }
   }
   
   cc.setSuperclass(cc.getSuperclass());
   cc.writeFile();
   
   result = true;
  } catch (NotFoundException e) {
   e.printStackTrace();
  } catch (CannotCompileException e) {
   e.printStackTrace();
  } catch(Exception e){
   e.printStackTrace();
  }
  return result;
 }
 
 private static String getGetter(String name,String type,CtClass cc){
  String result = null;
  String nstr = toUpLower(name);
  try {
   CtMethod m = cc.getDeclaredMethod("get" + nstr);
  } catch (NotFoundException e) {
   result = "public " + type
    + " get" + nstr + "(){"
    + "return " + name + ";"
    + "}";
  }
  return result;
 }

 private static String getSetter(String name,String type,CtClass cc){
  String result = null;
  String nstr = toUpLower(name);
  try {
   CtMethod m = cc.getDeclaredMethod("set" + nstr);
  } catch (NotFoundException e) {
   result = "public void"
    + " set" + nstr + "(" + type + " s){"
    + name + " = s;"
    + "}";
  }
  return result;
 }
 
 private static String toUpLower(String s){
  byte[] sarr = s.getBytes();
  sarr[0] = (byte)Character.toUpperCase((char)sarr[0]);
  return new String(sarr);
 }
}


このaddAccesorでは、調べるクラスの完全修飾名をStringとして引数に渡して呼び出します。これにより、そのクラスにあるpublicフィールドをすべてprivateに変更し、更にそのフィールドにアクセスするためのアクセサを作成します。作成できればtrueを、作成に失敗するとfalseを返すようにしています。

Getter/Setterメソッドのテキストは、getGetter/getSetterメソッドでそれぞれ作成しています。これらのメソッドでは、「getDeclaredMethod」というメソッドを利用しています。これは、引数に指定したメソッドがCtClassにあるかどうかチェックするものです。なければNotFoundExceptionという例外が発生します。これを利用し、NotFoundExceptionが発生したらまだメソッドが存在しないものとして、新たにメソッドのStringを生成してreturnさせています。

また、toUpLowerは、最初の1文字だけが大文字であとが小文字のStringを作成し返すものです。Getter/Setterは、例えば「test」というフィールドならば「getTest」「setTest」というような名前になりますから、1文字目だけを大文字にしたテキストを取得し、"set" + "Test"というようにしてメソッド名を得ればよい、というわけです。


  • 前のページへ
  • 1
  • 3
  • 4
  • 5
  • 次のページへ

あわせて読みたい

あなたにオススメ

    表示について

    カテゴリー一覧

    All Aboutサービス・メディア

    All About公式SNS
    日々の生活や仕事を楽しむための情報を毎日お届けします。
    公式SNS一覧
    © All About, Inc. All rights reserved. 掲載の記事・写真・イラストなど、すべてのコンテンツの無断複写・転載・公衆送信等を禁じます