尝试使用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()
答案 0 :(得分:25)
代码的问题在于getDeclaredMethod
函数通过名称和参数类型查找函数。通过电话
Method retrieveItems = clazz.getDeclaredMethod("retrieveItems");
代码将查找没有参数的方法retrieveItems()
。您正在寻找的方法确实采用了一个参数,一个字符串,因此您应该调用
Method retrieveItems = clazz.getDeclaredMethod("retrieveItems", String.class);
这将告诉Java搜索retrieveItems(String)
,这正是您正在寻找的。 p>
答案 1 :(得分:6)
为什么不简单地创建一个可以访问受保护方法的派生类,而不是使用那些棘手的反射内容?
有关进一步的想法,请参阅Is it bad practice to use Reflection in Unit testing?。
答案 2 :(得分:4)
如果您将测试版放在同一个软件包中(com.myapp
而不是com.myapp.tests
),他们可以访问受保护的(以及默认包成员。
然后您可以直接致电service.retrieveMembers(status)
。
如果您尝试将源与测试分开,通常最好使用不同的源目录(例如src
目录和test
目录。)
答案 3 :(得分:2)
不需要反思或继承:
将您的MyTestCase
置于包 com.myapp
下,因为“受保护”范围也是“包”。
然后MyTestCase
可以访问MyServiceImpl
的受保护方法。
答案 4 :(得分:2)
你应该在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");
}