Am trying to obtain and invoke a protected method residing in a different class and also different package using Java Reflection.
Class containing protected method:
package com.myapp;
public class MyServiceImpl {
protected List<String> retrieveItems(String status) {
// Implementation
}
}
Calling class:
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");
}
}
The compiler throws this Exception:
java.lang.NoSuchMethodException: com.myapp.MyServiceImpl.retrieveItems()
The problem with your code is that the getDeclaredMethod
function looks up a function both by name and by argument types. With the call
Method retrieveItems = clazz.getDeclaredMethod("retrieveItems");
The code will look for a method retrieveItems()
with no arguments. The method you're looking for does take an argument, a string, so you should call
Method retrieveItems = clazz.getDeclaredMethod("retrieveItems", String.class);
This will tell Java to search for retrieveItems(String)
, which is what you're looking for.
You should to use link to created object instead of link to class in invoke method and use Method.setAccessible(true) invocation for unlock access:
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");
}
Instead of using that tricky reflection stuff, why not simply create a derived class, which will have access to the protected method?
See Is it bad practice to use Reflection in Unit testing? for further thoughts.
If you put your testcases in the same package (com.myapp
instead of com.myapp.tests
) they will have access to protected (and default package level) members.
Then you can call service.retrieveMembers(status)
directly.
If you are trying to separate the source from the tests, its usually better to use a different source directory (for instance a src
directory and a test
directory).
No reflection or inheritance is needed:
Put your MyTestCase
under package com.myapp
, as scope 'protected' is also 'package'.
Then MyTestCase
can access protected methods of MyServiceImpl
.
精彩评论