Доступ к защищенному методу в тестовом примере с использованием Java Reflection
Я пытаюсь получить и вызывать защищенный метод, находящийся в другом классе, а также другой пакет с использованием 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()
Спасибо, что нашли время, чтобы прочитать это.
Ответы
Ответ 1
Проблема с вашим кодом заключается в том, что функция getDeclaredMethod
выполняет поиск функции как по имени, так и по типам аргументов. При вызове
Method retrieveItems = clazz.getDeclaredMethod("retrieveItems");
Код будет искать метод retrieveItems()
без аргументов. Метод, который вы ищете, принимает аргумент, строку, поэтому вы должны позвонить
Method retrieveItems = clazz.getDeclaredMethod("retrieveItems", String.class);
Это скажет Java для поиска retrieveItems(String)
, который вы ищете.
Ответ 2
Вместо использования этого сложного материала отражения, почему бы просто не создать производный класс, который будет иметь доступ к защищенному методу?
См. Неплохая практика использовать Reflection в модульном тестировании? для дальнейших мыслей.
Ответ 3
Если вы помещаете свои тестовые теги в один и тот же пакет (com.myapp
вместо com.myapp.tests
), они будут иметь доступ к элементам protected (и по умолчанию).
Затем вы можете напрямую вызвать service.retrieveMembers(status)
.
Если вы пытаетесь отделить источник от тестов, обычно лучше использовать другой исходный каталог (например, каталог src
и каталог test
).
Ответ 4
Не требуется никакого отражения или наследования:
Поместите ваш MyTestCase
в пакет com.myapp
, так как область действия "protected" также является "пакетом".
Затем MyTestCase
может получить доступ к защищенным методам MyServiceImpl
.
Ответ 5
Вам следует использовать ссылку на созданный объект вместо ссылки на класс в методе 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");
}