動的なメソッド実行

2010年04月10日 15時50分 Java



※対象バージョン:Java1.4

JavaBeans で定義されたオブジェクトからのインスタンス値の取得は、getXXX() メソッドを実行して行います。全てのインスタンス値を取得し、List や Map のオブジェクトを生成したい場合、getXXX() の名前がわかっていれば、オンコーディングすることは可能ですが、各 bean 毎にオンコーディングするのは大変ですし、共通機能として作成したいです。こういった名前の不明なメソッドを実行する方法が今回の内容です。

今回はメソッドを実行するまでのプロセスとして、以下の2つのケースを想定し説明します。

①新規にオブジェクトを生成してメソッドを実行するケース

  • クラスの取得
  • メソッドの取得
  • 対象オブジェクトの新規生成
  • メソッドの実行

②既存のオブジェクトのメソッドを実行するケース

  • クラスの取得
  • メソッドの取得
  • 対象オブジェクトの取得
  • メソッドの実行

どちらのケースでも実行するメソッドの Method オブジェクトの取得し、invoke() メソッドによりメソッドを実行します。

①新規にオブジェクトを生成してメソッドを実行するケース
テストクラスの全ての testXXX() メソッドを実行したい、夜間に登録された全てクラスを実行したい場合などがこのケースです。

1.クラスの取得
対象のオブジェクトと実行するメソッドのオブジェクトを Class オブジェクトより取得します。クラスオブジェクトはアプリケーション上のクラスパスから取得します。

Class c = Class.forName(クラスパス);

 
2.メソッドの取得
実行するメソッドのオブジェクトを取得します。取得にはメソッド名と引数の型を指定する方法と、全てのメソッドを取得する方法の2つがあります。

Method method = c.getMethod(メソッド名, 引数の型);
Method[] methods = c.getMethods();

 
3.対象オブジェクトの新規生成
メソッドを実行する対象のオブジェクトを新規に生成します。ただし static メソッドを実行する場合、オブジェクトの生成は不要です。

Constructor constructor = c.getConstructor(new Class[] {});
Object o = constructor.newInstance(new Object[] {});

 
4.メソッドの実行
invoke() でメソッドの実行します。instance メソッドの場合、オブジェクトを指定し、また引数が必要なメソッドの場合、引数を配列で指定します。

method.invoke(null, null);
methods[i].invoke(o, null);

 
サンプルコード

package jp.hrtdotnet.sample.javase;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class MethodSample {

    public static void staticMethod() {
        System.out.println("staticMethod value");
    }

    public void instanceMethod(String front, String rear) {
        System.out.println(front + " instanceMethod value " + rear);
    }

    public void testA() {
        System.out.println("testA value");
    }

    public void testB() {
        System.out.println("testB value");
    }

    // 実行されない
    public void getA() {
        System.out.println("getA value");
    }

    public static void main (String[] args) throws ClassNotFoundException,
            SecurityException, NoSuchMethodException,
            IllegalArgumentException, IllegalAccessException,
            InvocationTargetException, InstantiationException {

        // Class オブジェクトの取得
        Class c = Class.forName("jp.hrtdotnet.sample.javase.MethodSample");
        // Method オブジェクトの変数
        Method method = null;

        // static メソッドの実行
        // staticMethod() の取得
        method = c.getMethod("staticMethod", null);
        // メソッドの実行
        method.invoke(null, null);

        // instance メソッドの実行
        // オブジェクトの生成
        Constructor constructor = c.getConstructor(new Class[] {});
        Object o = constructor.newInstance(new Object[] {});
        // instanceMethod() の取得
        method = c.getMethod("instanceMethod", new Class[]{String.class, String.class});
        // メソッドの実行(引数に "mae", "ato" を渡す)
        method.invoke(o, new Object[]{"mae", "ato"});

        // 不特定多数のメソッドの取得
        Method[] methods = c.getMethods();
        for (int i = 0; i < methods.length; i++) {
            // "test" から始まるメソッドのみを対象
            if (methods[i].getName().startsWith("test")) {
                // 引数無しのメソッド、MethodSample クラスで宣言されたメソッド
                if (methods[i].getParameterTypes().length == 0 && 
                        methods[i].getDeclaringClass() == Class.forName("jp.hrtdotnet.sample.javase.MethodSample")) {
                    methods[i].invoke(o , null);
                }
            }
        }
    }
}


/******* プログラム実行結果 **********************************************************
 * staticMethod value
 * mae instanceMethod value ato
 * testA value
 * testB value
**************************************************************************************/

 
②既存のオブジェクトのメソッドを実行するケース
取得したオブジェクトの全ての getXXX() メソッドを実行したい場合などがこのケースです。対象オブジェクトの新規生成は不要、またクラスの取得は対象オブジェクトから行うこと以外は同じなので省略します。

サンプルコード

package jp.hrtdotnet.sample.javase;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class MethodSample2 {

    private String name;
    private String value;
    
    public MethodSample2(String name, String value) {
        this.name = name;
        this.value = value;
    }
    
    public String getName () {
        return this.name;
    }

    public String getValue () {
        return this.value;
    }

    public static void main (String[] args) throws SecurityException,
            NoSuchMethodException, IllegalArgumentException,
            IllegalAccessException, InvocationTargetException {

        // 実行するオブジェクトの生成
        MethodSample2 obj = new MethodSample2("MethodSample2", "メソッドサンプル2");

        // Class オブジェクトの取得
        Class c = obj.getClass();
        // メソッドの取得
        Method[] methods = c.getMethods();
        for (int i = 0; i < methods.length; i++) {
            // "get" から始まるメソッドのみを対象
            if (methods[i].getName().startsWith("get")) {
                // 引数無しのメソッド、MethodSample クラスで宣言されたメソッド
                if (methods[i].getParameterTypes().length == 0 && 
                        methods[i].getDeclaringClass() == obj.getClass()) {
                    System.out.println("name = " + methods[i].getName()
                        + ", value = " + (String)methods[i].invoke(obj, null));
                }
            }
        }
    }
}


/******* プログラム実行結果 **********************************************************
 * name = getName, value = MethodSample2
 * name = getValue, value = メソッドサンプル2
**************************************************************************************/

 

Class
static Class forName (String className)
          指定された文字列名を持つクラスまたはインタフェースに関連付けられた、Class オブジェクトを返します。
Constructor getConstructor (Class[] parameterTypes)
          Class オブジェクトが表すクラスの指定された public コンストラクタの Constructor オブジェクトを返します。
Method getMethod (String name, Class[] parameterTypes)
          Class オブジェクトが表すクラスまたはインタフェースの指定された public メンバメソッドの Method オブジェクトを返します。
Method[] getMethods ()

          Class オブジェクトが表すクラスまたはインタフェースのすべての public メンバメソッドの Method オブジェクトを格納している配列を返します。

Constructor
Object newInstance (Object[] initargs)
          指定された引数の値で、コンストラクタを実行し、オブジェクトを生成します。
Method
Object invoke (Object obj, Object[] args)
          Method オブジェクトのメソッドを、指定したオブジェクトに対して指定した値で呼び出します。
String getName ()
          Method オブジェクトのメソッドの名前を String として返します。
Class[] getParameterTypes ()

          Method オブジェクトのメソッドの引数の型を宣言順で Class オブジェクトの配列で返します。

Class getDeclaringClass ()
          Method オブジェクトのメソッドを宣言するクラスまたはインタフェースを表す Class オブジェクトを返します。


Leave a Reply

preload preload preload