package jp.terasoluna.fw.file.ut; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; /** * ◎ privateメソッドを呼び出すためのユーティリティクラス。 * @version 2003.08.29 */ class PrivateAccessUtil { /** * privateメソッド(staticでないもの)を呼び出す。<BR> * パラメータ0個~2個のメソッドには専用のメソッドが用意されているので、 そちらを利用した方がシンプルに記述できる。 * * <pre> * [使用例] * class Sample { * private int calcAdd(int val1, int val2, int val3) { * return val1 + val2 + val3; * } * } * * class SampleTest { * @SuppressWarnings("unchecked") public void testCalcAdd() { * Sample sample = new Sample(); * Integer result = (Integer) PrivateAccessUtil.invokePrivate( * sample, * "calcAdd", * new Class[] { int.class, int.class, int.class }, * new Object[] { new Integer(1), new Integer(2), * new Integer(3) } * ); * assertEquals(6, result.intValue()); * } * } * </pre> * * @param target 呼び出す対象のオブジェクト * @param methodName 呼び出したいメソッドの名前 * @param argTypes 引数の型の配列 * @param args 引数の値の配列。 int,boolean等の基本データ型は、Integer, Boolean等のラッパークラスに 格納して値を渡す必要あり。 * @return メソッドの戻り値。呼び出し側でダウンキャストが必要。 int, boolean等の基本データ型は、Integer, Boolean等の ラッパークラスに格納されて値が戻される。 * @throws Exception */ public static Object invokePrivate(Object target, String methodName, @SuppressWarnings("rawtypes") Class[] argTypes, Object[] args) throws Exception { // パラメータ値のチェック if (target == null) { throw new IllegalArgumentException(); } if (methodName == null || methodName.equals("")) { throw new IllegalArgumentException(); } if (argTypes.length != args.length) { throw new IllegalArgumentException(); } // privateメソッド呼び出し処理。 // スーパークラス全てについて呼び出しをトライする。 Class<?> c = target.getClass(); while (c != null) { try { Method method = c.getDeclaredMethod(methodName, argTypes); method.setAccessible(true); return method.invoke(target, args); } catch (InvocationTargetException e) { // 呼び出したメソッドが例外を投げた場合。 throw (Exception) e.getTargetException(); } catch (Exception e) { // 呼び出そうとしたメソッドが存在しなかった場合、何もしない。 // (親クラスで同じトライを繰り返す。) } c = c.getSuperclass(); } // 呼び出そうとしたメソッドが存在しなかった場合。 throw new NoSuchMethodException("Could not invoke " + target.getClass() .getName() + "." + methodName + "()"); } /** * privateメソッド(staticでないもの)を呼び出す(パラメータ0個用)。 * * <pre> * [使用例] * class Sample { * private int getString() { * return "success"; * } * } * * class SampleTest { * @SuppressWarnings("unchecked") public void testGetString() { * Sample sample = new Sample(); * String result = * (String) PrivateAccessUtil.invokePrivate(sample, "getString"): * assertEquals("success", result); * } * } * </pre> * * @param target 呼び出す対象のオブジェクト * @param methodName 呼び出したいメソッドの名前 * @return メソッドの戻り値。呼び出し側でダウンキャストが必要。 int, boolean等の基本データ型は、Integer, Boolean等の ラッパークラスに格納されて値が戻される。 * @throws Exception */ public static Object invokePrivate(Object target, String methodName) throws Exception { return invokePrivate(target, methodName, new Class[] {}, new Object[] {}); } /** * privateメソッド(staticでないもの)を呼び出す(パラメータ1個用)。 * * <pre> * [使用例] * class Sample { * private long square(long val) { * return val ˆ 2; * } * } * * class SampleTest { * @SuppressWarnings("unchecked") public void testSquare() { * Sample sample = new Sample(); * Long result = (Long) PrivateAccessUtil.invokePrivate( * sample, "square", long.class, new Long(2L)): * assertEquals(4, result.longValue()); * } * } * </pre> * * @param target 呼び出す対象のオブジェクト * @param methodName 呼び出したいメソッドの名前 * @param argType 引数の型 * @param arg 引数の値。 int,boolean等の基本データ型は、Integer, Boolean等のラッパークラスに 格納して値を渡す必要あり。 * @return メソッドの戻り値。呼び出し側でダウンキャストが必要。 int, boolean等の基本データ型は、Integer, Boolean等の ラッパークラスに格納されて値が戻される。 * @throws Exception */ public static Object invokePrivate(Object target, String methodName, Class<?> argType, Object arg) throws Exception { return invokePrivate(target, methodName, new Class[] { argType }, new Object[] { arg }); } /** * privateメソッド(staticでないもの)を呼び出す(パラメータ2個用)。 * * <pre> * [使用例] * class Sample { * private static int calcAdd(int val1, int val2) { * return val1 + val2; * } * } * * class SampleTest { * @SuppressWarnings("unchecked") public void testCalcAdd() { * Sample sample = new Sample(); * Integer result = (Integer) PrivateAccessUtil.invokePrivate( * sample, * "calcAdd", * int.class, * int.class, * new Integer(1), * new Integer(2) * ); * assertEquals(3, result.intValue()); * } * } * </pre> * * @param target 呼び出す対象のオブジェクト * @param methodName 呼び出したいメソッドの名前 * @param argType1 第一引数の型 * @param argType2 第二引数の型 * @param arg1 第一引数の値。 int,boolean等の基本データ型は、Integer, Boolean等のラッパークラスに 格納して値を渡す必要あり。 * @param arg2 第二引数の値。 * @return メソッドの戻り値。呼び出し側でダウンキャストが必要。 int, boolean等の基本データ型は、Integer, Boolean等の ラッパークラスに格納されて値が戻される。 * @throws Exception */ public static Object invokePrivate(Object target, String methodName, Class<?> argType1, Class<?> argType2, Object arg1, Object arg2) throws Exception { return invokePrivate(target, methodName, new Class[] { argType1, argType2 }, new Object[] { arg1, arg2 }); } /** * staticなprivateメソッドを呼び出す。 <BR> * <BR> * パラメータ0個~2個のメソッドには専用のメソッドが用意されているので、 そちらを利用した方がシンプルに記述できる。 * * <pre> * [使用例] * class Sample { * private static int calcAdd(int val1, int val2, int val3) { * return val1 + val2 + val3; * } * } * * class SampleTest { * @SuppressWarnings("unchecked") public void testCalcAdd() { * Integer result = (Integer) PrivateAccessUtil.invokePrivate( * Sample.class, * "calcAdd", * new Class[] { int.class, int.class, int.class }, * new Object[] { new Integer(1), new Integer(2), * new Integer(3) } * ); * assertEquals(6, result.intValue()); * } * } * </pre> * * @param target 呼び出す対象のクラス * @param methodName 呼び出したいメソッドの名前 * @param argTypes 引数の型の配列 * @param args 引数の値の配列。 int,boolean等の基本データ型は、Integer, Boolean等のラッパークラスに 格納して値を渡す必要あり。 * @return メソッドの戻り値。呼び出し側でダウンキャストが必要。 int, boolean等の基本データ型は、Integer, Boolean等の ラッパークラスに格納されて値が戻される。 * @throws Exception */ public static Object invokePrivate(Class<?> target, String methodName, @SuppressWarnings("rawtypes") Class[] argTypes, Object[] args) throws Exception { // パラメータ値のチェック if (target == null) { throw new IllegalArgumentException(); } if (methodName == null || methodName.equals("")) { throw new IllegalArgumentException(); } if (argTypes.length != args.length) { throw new IllegalArgumentException(); } // privateメソッド呼び出し処理。 // スーパークラス全てについて呼び出しをトライする。 Class<?> c = target; while (c != null) { try { Method method = c.getDeclaredMethod(methodName, argTypes); method.setAccessible(true); return method.invoke(target, args); } catch (InvocationTargetException e) { // 呼び出したメソッドが例外を投げた場合。 throw (Exception) e.getTargetException(); } catch (Exception e) { // 呼び出そうとしたメソッドが存在しなかった場合、何もしない。 // (親クラスで同じトライを繰り返す。) } c = c.getSuperclass(); } // 呼び出そうとしたメソッドが存在しなかった場合。 throw new NoSuchMethodException("Could not invoke " + target.getClass() .getName() + "." + methodName + "()"); } /** * staticなprivateメソッドを呼び出す(パラメータ0個用)。 * * <pre> * [使用例] * class Sample { * private static int getString() { * return "success"; * } * } * * class SampleTest { * @SuppressWarnings("unchecked") public void testGetString() { * String result = (String) PrivateAccessUtil.invokePrivate( * Sample.class, "getString"): * assertEquals("success", result); * } * } * </pre> * * @param target 呼び出す対象のクラス * @param methodName 呼び出したいメソッドの名前 * @return メソッドの戻り値。呼び出し側でダウンキャストが必要。 int, boolean等の基本データ型は、Integer, Boolean等の ラッパークラスに格納されて値が戻される。 * @throws Exception */ public static Object invokePrivate(Class<?> target, String methodName) throws Exception { return invokePrivate(target, methodName, new Class[] {}, new Object[] {}); } /** * staticなprivateメソッドを呼び出す(パラメータ1個用)。 * * <pre> * [使用例] * class Sample { * private static long square(long val) { * return val ˆ 2; * } * } * * class SampleTest { * @SuppressWarnings("unchecked") public void testSquare() { * Long result = (Long) PrivateAccessUtil.invokePrivate( * Sample.class, "square", long.class, new Long(2L)): * assertEquals(4, result.longValue()); * } * } * </pre> * * @param target 呼び出す対象のクラス * @param methodName 呼び出したいメソッドの名前 * @param argType 引数の型 * @param arg 引数の値。 int,boolean等の基本データ型は、Integer, Boolean等のラッパークラスに 格納して値を渡す必要あり。 * @return メソッドの戻り値。呼び出し側でダウンキャストが必要。 int, boolean等の基本データ型は、Integer, Boolean等の ラッパークラスに格納されて値が戻される。 * @throws Exception */ public static Object invokePrivate(Class<?> target, String methodName, Class<?> argType, Object arg) throws Exception { return invokePrivate(target, methodName, new Class[] { argType }, new Object[] { arg }); } /** * staticなprivateメソッドを呼び出す(パラメータ2個用)。 * * <pre> * [使用例] * class Sample { * private static int calcAdd(int val1, int val2) { * return val1 + val2; * } * } * * class SampleTest { * @SuppressWarnings("unchecked") public void testCalcAdd() { * Integer result = (Integer) PrivateAccessUtil.invokePrivate( * Sample.class, * "calcAdd", * int.class, * int.class, * new Integer(1), * new Integer(2) * ); * assertEquals(3, result.intValue()); * } * } * </pre> * * @param target 呼び出す対象のクラス * @param methodName 呼び出したいメソッドの名前 * @param argType1 第一引数の型 * @param argType2 第二引数の型 * @param arg1 第一引数の値。 int,boolean等の基本データ型は、Integer, Boolean等のラッパークラスに 格納して値を渡す必要あり。 * @param arg2 第二引数の値。 * @return メソッドの戻り値。呼び出し側でダウンキャストが必要。 int, boolean等の基本データ型は、Integer, Boolean等の ラッパークラスに格納されて値が戻される。 * @throws Exception */ public static Object invokePrivate(Class<?> target, String methodName, Class<?> argType1, Class<?> argType2, Object arg1, Object arg2) throws Exception { return invokePrivate(target, methodName, new Class[] { argType1, argType2 }, new Object[] { arg1, arg2 }); } }