2011年2月27日日曜日

[Java]プライベートクラスをインスタンス化する

そもそもユニットテストを前提とした設計をしていないのが問題なんですが、ユニットテストで、特定のクラスの内部クラスを実行しなければいけない場合に遭遇しました。
メンバ変数に保持していれば、リフレクションで取り出すことができるので、実行も比較的楽なんですが、コレがメソッド内のみで利用されている場合、この内部クラスを外部からインスタンス化する必要があります。
ちょっと面倒ですが、外部からインスタンス化する方法を紹介します。

■インスタンス化するコード
try {
    TargetClass target = new TargetClass();

    //配列の0番目は決めうち
    Class<?> clss = TargetClass.class.getDeclaredClasses()[0];

    //コンストラクタを取り出す。引数はそのアウタークラスになる
    Constructor<?> cons = clss.getDeclaredConstructor(new Class[]{TargetClass.class});

    //コンストラクタを使ってインスタンスを生成する
    cons.setAccessible(true);
    Object inner = cons.newInstance(new Object[]{target});

    //メソッド実行
    System.out.println(inner.toString());

catch (SecurityException e) {
catch (NoSuchMethodException e) {
catch (IllegalArgumentException e) {
catch (InstantiationException e) {
catch (IllegalAccessException e) {
catch (InvocationTargetException e) {
}

第一引数が該当のクラスのアウタークラスになるのがルール。

■ターゲットのクラス(例)

public class TargetClass {

    public void doExec(){

        new TargetInnerClass().subExec();
    }

    //このクラスの単体テストが難しい...
    private class TargetInnerClass{
        public void subExec(){

        }
    }
}

1 件のコメント:

師子乃 さんのコメント...

こんにちは。

テストを考慮した設計、重要ですね!