2011年1月14日金曜日

[Java]プライベートメソッドを呼び出す

UnitTestなどでprivateメソッドをコードを修正せずに実行しようとした場合、該当のprivateメソッドを使っているpublicなメソッドを呼び出すか、リフレクションを利用するしかありません。
リフレクションを利用する場合、クラスの型情報を指定する必要がありますが、いちいち指定するのが面倒です。というとで、なかったら再起で呼び出すロジックを組んでみました。コードはこんな感じ。

/**
 * プライベートメソッド(引数なし)を呼び出します。
 *
 * @param obj インスタンス
 * @param name メソッド名
 * @return 戻り値
 * @throws Throwable プライベートメソッドから発生した例外
 */

public static Object invoke(Object obj, String name) throws Throwable {

    Object result = invoke(obj, new Object[0], name, new Class[0]);
    return result;
}

/**
 * プライベートメソッドを呼び出します。
 *
 * @param obj インスタンス
 * @param args 引数
 * @param name メソッド名
 * @param parameterTypes 引数タイプ
 * @return 戻り値
 * @throws Throwable プライベートメソッドから発生した例外
 */

public static Object invoke(Object obj, Object[] args, String name,
        Class<?>[] parameterTypes) throws Throwable {

    Object result = invoke(obj.getClass(), obj, args, name, parameterTypes);
    return result;
}

/**
 * プライベートメソッドを呼び出します。
 *
 * @param cls クラス
 * @param objインスタンス
 * @param args 引数
 * @param name メソッド名
 * @param parameterTypes 引数タイプ
 * @return 戻り値
 * @throws Throwable プライベートメソッドから発生した例外
 */

public static Object invoke(Class<?> cls, Object obj, Object[] args, String name, Class<?>[] parameterTypes) throws Throwable {

    Object result = null;

    do{
        try {
            Method method = cls.getDeclaredMethod(name, parameterTypes);
            method.setAccessible(true);

            result = method.invoke(obj, args);
            break;

        } catch (NoSuchMethodException e) {
            //親クラスの型でリトライ
            cls = cls.getSuperclass();
        } catch (InvocationTargetException e) {
            throw e.getCause();
        } catch (Throwable e) {
            e.printStackTrace();
            break;
        }
    }while(cls != null);

    return result;
}

0 件のコメント: