Java Reflectionを使用して、別のクラスおよび別のパッケージにある保護されたメソッドを取得して呼び出しようとしています。
保護されたメソッドを含むクラス:
package com.myapp;
public class MyServiceImpl {
protected List<String> retrieveItems(String status) {
// Implementation
}
}
呼び出しクラス:
package xxx.myapp.tests;
import com.myapp.MyServiceImpl;
public class MyTestCase {
List<String> items;
public void setUp() throws Exception {
MyServiceImpl service = new MyServiceImpl();
Class clazz = service.getClass();
// Fails at the next line:
Method retrieveItems = clazz.getDeclaredMethod("retrieveItems");
// How to invoke the method and return List<String> items?
// tried this but it fails?
retrieveItems.invoke(clazz, "S");
}
}
コンパイラは次の例外をスローします。
Java.lang.NoSuchMethodException: com.myapp.MyServiceImpl.retrieveItems()
コードの問題は、getDeclaredMethod
関数が名前と引数タイプの両方で関数を検索することです。電話で
_Method retrieveItems = clazz.getDeclaredMethod("retrieveItems");
_
コードは、引数のないメソッドretrieveItems()
を探します。あなたが探しているメソッドは引数、文字列を取るので、あなたは呼び出す必要があります
_Method retrieveItems = clazz.getDeclaredMethod("retrieveItems", String.class);
_
これにより、JavaはretrieveItems(String)
を検索するように指示されます。これは、探しているものです。
そのトリッキーなリフレクションを使用する代わりに、保護されたメソッドにアクセスできる派生クラスを作成してみませんか?
詳細については、 ユニットテストでReflectionを使用するのは悪い習慣ですか? を参照してください。
テストケースを同じパッケージ(_com.myapp
_ではなく_com.myapp.tests
_)に入れると、テストケースはprotected(およびdefaultパッケージレベル)メンバーにアクセスできるようになります。 。
次に、service.retrieveMembers(status)
を直接呼び出すことができます。
ソースをテストから分離しようとしている場合は、通常、別のソースディレクトリ(たとえば、src
ディレクトリとtest
ディレクトリ)を使用することをお勧めします。
リフレクションや継承は必要ありません:
スコープ「protected」も「package」であるため、MyTestCase
をpackagecom.myapp
の下に置きます。次に、MyTestCase
はMyServiceImpl
の保護されたメソッドにアクセスできます。
Invokeメソッドのクラスへのリンクではなく、作成されたオブジェクトへのリンクを使用し、ロック解除アクセスにMethod.setAccessible(true)呼び出しを使用する必要があります。
public void setUp() throws Exception {
MyServiceImpl service = new MyServiceImpl();
Class<?> clazz = service.getClass();
Method retrieveItems = clazz.getDeclaredMethod("retrieveItems", String.class);
retrieveItems.setAccessible(true);
items = (List<String>)retrieveItems.invoke(service, "S");
}