Казалось бы ответ очевиден:
(new Reflections("package")).getSubTypesOf(SuperClass.class)
Однако эта конструкция находит не всех наследников, в случае, если иерархия разнесена на несколько пакетов.
Есть следующие классы:
package1.ParentClass extemds SuperClass
package2.ChildClass extends ParentClass
Пакеты package1 и package2 не вложенные.
Конструкция
(new Reflections("package1")).getSubTypesOf(SuperClass.class)
Ожидаемо вернёт package1.ParentClass
А вот конструкция
(new Reflections("package2")).getSubTypesOf(SuperClass.class)
Наш package2.ChildClass не вернёт, хотя это очевидный наследник SuperClass
Я понимаю. что могу в ручную пробежаться по всем классам пакета и собрать нужные. Но неужели нет стандартного способа?
И ещё, объясните, почему по умолчанию ChildClass не находится? Для меня это было очень неожиданное поведение от org.reflections.Reflections
UPD:
Изучил исходники ядра org.reflections, всё стало на свои места.
Если кратко, java именно так и реализует Reflections.
У каждого класса в рефлексии есть только ссылка на родителя. Поэтому поиск подклассов в любом случае перебор.
Почему в этом переборе нет супер классов из иных пакетов - вопрос отдельный. Так реализовано.
Для каждой конкретной задачи нужно использовать оптимальное решение. Но хотелось бы услышать о уже существующих решениях, которые позволяют найти всех потомков, кроме java org.reflections.
UPD: Ещё один интересный и нетрудоёмкий способ.
Reflections reflections = new Reflections("package1", new SubTypesScanner())
Set
Данное решение перебирает все классы пакета (кроме наследников object)
reflections.getStore().get(SubTypesScanner.class.getSimpleName()).values()
и проверяет на то, что они являются наследником или реализуют SuperClass
SuperClass.class.isAssignableFrom(subType)
По производительности, по крайней мере, лучше, чем поиск по всем пакетам и последующая фильтрация
Ответ
И ещё, объясните, почему по умолчанию ChildClass не находится?
Причина в том, что класс ChildClass является не прямым наследником SuperClass, а через класс ParentClass.
Reflections не уходит рекурсивно на проверку "родителей-родителей" и так далее, поэтому для обнаружения факта наследования через "промежуточные" классы необходимо загрузить пакеты со всеми "промежуточными" классами. В данном случае для того чтобы определить факт наследования ChildClass от SuperClass необходимо так же загрузить ParentClass. Лишние классы из полученного множества(Set) можно отфильтровать по имени пакета.
(new Reflections("package1","package2"))
.getSubTypesOf(SuperClass.class)
.stream()
.filter(c->c.getPackage().getName().equals("package2")).collect(Collectors.toSet());
1) Если неизвестен пакет "package1" то можно загрузить реализации из всех пакетов и потом отфильтровать по нужному пакету "package2":
Set
или
Set
2) В качестве более производительной альтернативы можно воспользоваться стандартными средствами “java core” и получить все файлы-классы пакета и их уже рекурсивно проверить на наличие искомого наследника.
public static Set
public static boolean checkAllParents(Class type, Class hasParentType) {
Class parent = type.getSuperclass();
if (parent == Object.class) {
return false;
}
if (parent.getClass() == hasParentType.getClass()) {
return true;
}
return checkAllParents(parent, hasParentType);
}
Set
Комментариев нет:
Отправить комментарий