Чи можете ви знайти всі класи в пакеті, використовуючи роздуми?


527

Чи можливо знайти всі класи чи інтерфейси в даному пакеті? (Швидко дивлячись, наприклад Package, здається, що ні.)


2
FYI рішення Amit посилається на твори, хоча воно має помилку, якщо шлях класу має пробільний символ (і, мабуть, і для інших не буквено-цифрових символів). якщо ви використовуєте його в будь-якому виробничому коді, дивіться мій коментар до його відповіді для вирішення.
Кіп

2
Також відзначте цю публікацію .
barfuin

1
Див відповідну відповідь: stackoverflow.com/a/30149061/4102160
CFX

1
Також відзначте цю публікацію .
sp00m

1
Дивіться мою відповідь нижче про ClassGraph, це на даний момент найбільш надійний метод сканування шляху до класу та модуля.
Люк Хатчісон

Відповіді:


373

Зважаючи на динамічний характер навантажувачів класу, це неможливо. Навантажувачі класів не зобов’язані вказувати ВМ, які класи він може надати, натомість вони просто передають запити для класів, і повинні повернути клас або викинути виняток.

Однак, якщо ви пишете власні навантажувачі класів або вивчаєте класні шляхи та це банки, цю інформацію можна знайти. Це буде через операції з файловою системою, але не відображення. Можливо, навіть існують бібліотеки, які допоможуть вам це зробити.

Якщо є класи, які генеруються або доставляються віддалено, ви не зможете виявити ці класи.

Звичайний метод - це замість того, щоб десь зареєструвати класи, до яких потрібно отримати доступ у файлі, або посилати їх на інший клас. Або просто використовувати умовність, коли справа стосується іменування.

Додаток: Бібліотека роздумів дозволить вам шукати класи в поточному класі. З його допомогою можна отримати всі класи в пакеті:

 Reflections reflections = new Reflections("my.project.prefix");

 Set<Class<? extends Object>> allClasses = 
     reflections.getSubTypesOf(Object.class);

12
Неможливість запитувати назви класів мене давно клопоче. Звичайно, це важко, а продуктивність може бути різною, і для певних завантажувачів класу список не визначений або необмежений, але є способи, над якими це можна було б обробити.
Містер Блискучі та Нові 安 宇

16
Зауважте, що це рішення не працюватиме, оскільки за замовчуванням getSubTypesOf не повертає підтипи Object. Див рішення Aleksander Blomskøld про те, як налаштувати SubTypeScanner.
Алекс Спрінглінг

17
Роздумів вимагає Гуава. Гуава велика. Версія 14.0.1 становить 2,1 Мб.
Майк Джонс

3
Не працювали для мене. Mac OSX - залежність відбиття версії 0.9.9-RC1 (maven) - JDK 1.7. Перегляньте прийняту відповідь. @ AleksanderBlomskøld відповідь - це те, що потрібно. !!!!!
Константинос Маргаритис

68
Якщо це повертає порожній список, ініціалізуйте об'єкт Reflections таким чином: Reflections reflections = new Reflections ("your.package.here", новий SubTypesScanner (false));
Жоао Роша да Сілва

186

Вам, мабуть, варто поглянути на бібліотеку Reflections з відкритим кодом . За допомогою нього ви можете легко досягти того, що хочете.

Спочатку встановіть індекс віддзеркалень (це трохи безладно, оскільки пошук усіх класів вимкнено за замовчуванням):

List<ClassLoader> classLoadersList = new LinkedList<ClassLoader>();
classLoadersList.add(ClasspathHelper.contextClassLoader());
classLoadersList.add(ClasspathHelper.staticClassLoader());

Reflections reflections = new Reflections(new ConfigurationBuilder()
    .setScanners(new SubTypesScanner(false /* don't exclude Object.class */), new ResourcesScanner())
    .setUrls(ClasspathHelper.forClassLoader(classLoadersList.toArray(new ClassLoader[0])))
    .filterInputsBy(new FilterBuilder().include(FilterBuilder.prefix("org.your.package"))));

Тоді ви можете здійснити запит для всіх об’єктів у заданому пакеті:

Set<Class<?>> classes = reflections.getSubTypesOf(Object.class);

6
Ах, ось ми: code.google.com/p/reflections/isissue/detail?id=122 . Об'єкт за замовчуванням виключається, але його можна повторно змінити. Дякую, що вказали мені на цю бібліотеку, це чудово!
mtrc

1
Я зіткнувся з проблемами на своєму Mac з цим кодом (пов’язаним із рідними бібліотеками), але використання .addUrls(ClasspathHelper.forJavaClassPath())замість вищесказаного вирішило їх для мене. Менше коду!
David Pärsson

3
якщо хтось задається питанням про найпростіший спосіб отримати пакет за замовчуванням - це те, що префікс буде порожнім рядком -> "".
JBA

2
Бібліотека "Роздуми" має складну ліцензію: github.com/ronmamo/reflections/blob/master/COPYING.txt . Хитрість полягає в тому, що ліцензія дозволяє безкоштовно використовувати лише саму ліцензію. Щоб дійсно користуватися бібліотекою (а не ліцензією), кожен повинен зв’язатися з автором та домовитись про умови використання.
Серж Рогач

3
Серж, я думаю, що ви неправильно розумієте WTFPL: wtfpl.net Я думаю, що WTFPL означає, що ви можете робити все, що завгодно, не тільки з ліцензією, але і з кодом, а також
Рішо,

122

Google Guava 14 включає новий клас ClassPathз трьома методами сканування для класів вищого рівня:

  • getTopLevelClasses()
  • getTopLevelClasses(String packageName)
  • getTopLevelClassesRecursive(String packageName)

Для отримання додаткової інформації див. ClassPathJavadocs .


це працювало для мене там, де Рефлексія не могла зробити (немає загального прямого предка, немає загальної анотації)
Ріккардо Коссу

1
Як я вже згадував у коментарі нижче , ClassPathвін позначений тегами @Beta, тому для деяких може бути не дуже хорошою ідеєю ...
Крістіан

1
Сказавши, що це працює там, де рефлексія не робить, є дещо дивним, рішення, безперечно, реалізується за допомогою функцій відображення (і завантажувача класів).
Maarten Bodewes

5
Я думаю, що він мав на увазі бібліотеку Роздумів, згадану в іншій відповіді.
Крістоф Лейтер

Працює під Java 11, якщо використовується версія guava 28.1-jre.
gorjanz

111

Ви можете використовувати цей спосіб 1, який використовує ClassLoader.

/**
 * Scans all classes accessible from the context class loader which belong to the given package and subpackages.
 *
 * @param packageName The base package
 * @return The classes
 * @throws ClassNotFoundException
 * @throws IOException
 */
private static Class[] getClasses(String packageName)
        throws ClassNotFoundException, IOException {
    ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
    assert classLoader != null;
    String path = packageName.replace('.', '/');
    Enumeration<URL> resources = classLoader.getResources(path);
    List<File> dirs = new ArrayList<File>();
    while (resources.hasMoreElements()) {
        URL resource = resources.nextElement();
        dirs.add(new File(resource.getFile()));
    }
    ArrayList<Class> classes = new ArrayList<Class>();
    for (File directory : dirs) {
        classes.addAll(findClasses(directory, packageName));
    }
    return classes.toArray(new Class[classes.size()]);
}

/**
 * Recursive method used to find all classes in a given directory and subdirs.
 *
 * @param directory   The base directory
 * @param packageName The package name for classes found inside the base directory
 * @return The classes
 * @throws ClassNotFoundException
 */
private static List<Class> findClasses(File directory, String packageName) throws ClassNotFoundException {
    List<Class> classes = new ArrayList<Class>();
    if (!directory.exists()) {
        return classes;
    }
    File[] files = directory.listFiles();
    for (File file : files) {
        if (file.isDirectory()) {
            assert !file.getName().contains(".");
            classes.addAll(findClasses(file, packageName + "." + file.getName()));
        } else if (file.getName().endsWith(".class")) {
            classes.add(Class.forName(packageName + '.' + file.getName().substring(0, file.getName().length() - 6)));
        }
    }
    return classes;
}

__________
1 Цей метод був узятий спочатку з http://snippets.dzone.com/posts/show/4831 , який був заархівований Інтернет-архівом, як пов’язано з цим. Фрагмент також доступний за посиланням https://dzone.com/articles/get-all-classes-within-package .


6
У мене виникли проблеми з цим, якщо мій шлях містив пробіли. Клас URL уникає пробілів до %20, але new File()конструктор трактував це як буквальний знак відсотка два нулі. Я виправив це, змінивши dirs.add(...)рядок на це: dirs.add(new File(resource.toURI())); Це також означало, що я повинен був додати URISyntaxExceptionпункт про кидкиgetClasses
Kip

19
Ви щойно скопіювали з dzone.com/articles/get-all-classes-within-package ! будь ласка, зверніться до джерела наступного разу
RS

19
+1, оскільки для цього рішення НЕ потрібні зовнішні бібліотеки ... НІКОЛИ, дійсно НІКОЛИ не з’єднуйте свій код випадковим чином з бібліотеками, щоб досягти такої дрібниці, як ця. чи знаєте ви, що ви додаєте потенційну поверхню атаки для нападників? Листопада 2015 проблема Apache Commons виявив , що призводить до віддаленого виконання команд тільки при наявності Apache Commons в шляху до класів додатки , розгорнутого на JBoss / Weblogic [ foxglovesecurity.com/2015/11/06 / ...
sc0p

@Qix правильно зазначив, що цей код не підтримує jar. Для того, щоб підтримувати банки та каталоги . Код було змінено, як зазначено нижче:
user1523177

1
Гарне рішення, але здається, що краще, якщо "Class.forName (String className)" буде замінено на "Class.forName (String className, булева ініціалізація, завантажувач ClassLoader)", де "ініціалізувати = false;" щоб не створювати екземпляри класу.
Андрій_N

99

Весна

Цей приклад призначений для Spring 4, але сканер класового шляху ви також можете знайти в більш ранніх версіях.

// create scanner and disable default filters (that is the 'false' argument)
final ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(false);
// add include filters which matches all the classes (or use your own)
provider.addIncludeFilter(new RegexPatternTypeFilter(Pattern.compile(".*")));

// get matching classes defined in the package
final Set<BeanDefinition> classes = provider.findCandidateComponents("my.package.name");

// this is how you can load the class type from BeanDefinition instance
for (BeanDefinition bean: classes) {
    Class<?> clazz = Class.forName(bean.getBeanClassName());
    // ... do your magic with the class ...
}

Google Guava

Примітка. У версії 14 API все ще позначений як @Beta , тому будьте обережні у виробничому коді.

final ClassLoader loader = Thread.currentThread().getContextClassLoader();

for (final ClassPath.ClassInfo info : ClassPath.from(loader).getTopLevelClasses()) {
  if (info.getName().startsWith("my.package.")) {
    final Class<?> clazz = info.load();
    // do something with your clazz
  }
}

5
Відмінна відповідь. Тут занадто багато рішень, які є багатослівними, не перевіреними, непрацюючими! Цей фантастичний: він лаконічний і перевірений (він від Гуави). Дуже добре! Це корисно, воно заслуговує на більшу кількість нагород.
JeanValjean

На жаль, ClassPathклас у Guava також позначений так @Beta: "API, позначені анотацією @Beta на рівні класу чи методу, можуть змінюватися. Вони можуть бути змінені будь-яким способом або навіть видалені в будь-якому великому випуску. Якщо ваш код - це сама бібліотека (тобто вона використовується в CLASSPATH користувачів поза вашим власним контролем), ви не повинні використовувати бета-версії API, якщо ви не перепаковуєте їх ... " code.google.com/p/guava-libraries/#Important_Warnings
Крістіан

@Christian Добре, я не помітив! Дякую. Я додам ще одну відповідь за допомогою сканера Spring classpath, який точно не є бета-версією.
voho

Для пошуку вкладених статичних класів за допомогою рішення guava getAllClasses()можна використовувати метод.
v.ladynev

1
Рішення Spring - це єдине працююче, якщо запускається з виконуваної банки.
Лука

38

Привіт. У мене завжди були проблеми з рішеннями вище (і на інших сайтах).
Я, як розробник, програмую аддон для API. API забороняє використовувати будь-які зовнішні бібліотеки чи сторонні інструменти. Установка також складається з суміші коду в jar-zip-файлах та файлів класів, розташованих безпосередньо в деяких каталогах. Таким чином, мій код повинен був мати змогу вирішувати всі налаштування. Після багатьох досліджень я придумав метод, який буде працювати принаймні в 95% усіх можливих налаштувань.

Наступний код - це в основному метод overkill, який завжди буде працювати.

Код:

Цей код сканує даний пакет для всіх класів, що входять до нього. Він буде працювати тільки для всіх класів в поточному ClassLoader.

/**
 * Private helper method
 * 
 * @param directory
 *            The directory to start with
 * @param pckgname
 *            The package name to search for. Will be needed for getting the
 *            Class object.
 * @param classes
 *            if a file isn't loaded but still is in the directory
 * @throws ClassNotFoundException
 */
private static void checkDirectory(File directory, String pckgname,
        ArrayList<Class<?>> classes) throws ClassNotFoundException {
    File tmpDirectory;

    if (directory.exists() && directory.isDirectory()) {
        final String[] files = directory.list();

        for (final String file : files) {
            if (file.endsWith(".class")) {
                try {
                    classes.add(Class.forName(pckgname + '.'
                            + file.substring(0, file.length() - 6)));
                } catch (final NoClassDefFoundError e) {
                    // do nothing. this class hasn't been found by the
                    // loader, and we don't care.
                }
            } else if ((tmpDirectory = new File(directory, file))
                    .isDirectory()) {
                checkDirectory(tmpDirectory, pckgname + "." + file, classes);
            }
        }
    }
}

/**
 * Private helper method.
 * 
 * @param connection
 *            the connection to the jar
 * @param pckgname
 *            the package name to search for
 * @param classes
 *            the current ArrayList of all classes. This method will simply
 *            add new classes.
 * @throws ClassNotFoundException
 *             if a file isn't loaded but still is in the jar file
 * @throws IOException
 *             if it can't correctly read from the jar file.
 */
private static void checkJarFile(JarURLConnection connection,
        String pckgname, ArrayList<Class<?>> classes)
        throws ClassNotFoundException, IOException {
    final JarFile jarFile = connection.getJarFile();
    final Enumeration<JarEntry> entries = jarFile.entries();
    String name;

    for (JarEntry jarEntry = null; entries.hasMoreElements()
            && ((jarEntry = entries.nextElement()) != null);) {
        name = jarEntry.getName();

        if (name.contains(".class")) {
            name = name.substring(0, name.length() - 6).replace('/', '.');

            if (name.contains(pckgname)) {
                classes.add(Class.forName(name));
            }
        }
    }
}

/**
 * Attempts to list all the classes in the specified package as determined
 * by the context class loader
 * 
 * @param pckgname
 *            the package name to search
 * @return a list of classes that exist within that package
 * @throws ClassNotFoundException
 *             if something went wrong
 */
public static ArrayList<Class<?>> getClassesForPackage(String pckgname)
        throws ClassNotFoundException {
    final ArrayList<Class<?>> classes = new ArrayList<Class<?>>();

    try {
        final ClassLoader cld = Thread.currentThread()
                .getContextClassLoader();

        if (cld == null)
            throw new ClassNotFoundException("Can't get class loader.");

        final Enumeration<URL> resources = cld.getResources(pckgname
                .replace('.', '/'));
        URLConnection connection;

        for (URL url = null; resources.hasMoreElements()
                && ((url = resources.nextElement()) != null);) {
            try {
                connection = url.openConnection();

                if (connection instanceof JarURLConnection) {
                    checkJarFile((JarURLConnection) connection, pckgname,
                            classes);
                } else if (connection instanceof FileURLConnection) {
                    try {
                        checkDirectory(
                                new File(URLDecoder.decode(url.getPath(),
                                        "UTF-8")), pckgname, classes);
                    } catch (final UnsupportedEncodingException ex) {
                        throw new ClassNotFoundException(
                                pckgname
                                        + " does not appear to be a valid package (Unsupported encoding)",
                                ex);
                    }
                } else
                    throw new ClassNotFoundException(pckgname + " ("
                            + url.getPath()
                            + ") does not appear to be a valid package");
            } catch (final IOException ioex) {
                throw new ClassNotFoundException(
                        "IOException was thrown when trying to get all resources for "
                                + pckgname, ioex);
            }
        }
    } catch (final NullPointerException ex) {
        throw new ClassNotFoundException(
                pckgname
                        + " does not appear to be a valid package (Null pointer exception)",
                ex);
    } catch (final IOException ioex) {
        throw new ClassNotFoundException(
                "IOException was thrown when trying to get all resources for "
                        + pckgname, ioex);
    }

    return classes;
}

Ці три методи дають вам можливість знаходити всі класи в заданому пакеті.
Ви використовуєте його так:

getClassesForPackage("package.your.classes.are.in");

Пояснення:

Спосіб спочатку отримує струм ClassLoader. Потім він отримує всі ресурси, які містять згаданий пакет та ітерації цих URLs. Потім він створює a URLConnectionі визначає, який тип URl у нас є. Це може бути або каталог ( FileURLConnection), або каталог всередині jar-файлу або zip-файл ( JarURLConnection). Залежно від того, який тип з'єднання у нас буде називатися два різні методи.

Спочатку давайте подивимось, що станеться, якщо це FileURLConnection.
Він спочатку перевіряє, чи є переданий файл, і чи це каталог. Якщо це так, він перевіряє, чи це файл класу. Якщо так, Classоб’єкт буде створений і поміщений у ArrayList. Якщо це не файл класу, а це каталог, ми просто перебираємо його в нього і робимо те ж саме. Усі інші випадки / файли будуть ігноровані.

Якщо URLConnectionце JarURLConnectionінший приватний помічник, буде викликаний метод. Цей метод повторює всі записи в архіві zip / jar. Якщо один запис є файлом класу і знаходиться всередині пакета, Classоб'єкт буде створений і збережений у ArrayList.

Після розбору всіх ресурсів він (основний метод) повертає ArrayListмістити всі класи в даному пакеті, про які ClassLoaderзнає поточний .

Якщо процес не вдасться в будь-який момент, а ClassNotFoundExceptionбуде викинуто детальну інформацію про точну причину.


4
Цей приклад вимагає імпорту sun.net.www.protocol.file.FileURLConnection, який генерує попередження під час компіляції ("попередження: sun.net.www.protocol.file.FileURLConnection є фірмовим API Sun і може бути видалений у майбутньому випуску"). Чи є альтернатива використанню цього класу, або попередження можна придушити за допомогою приміток?
Крістіан

Цей метод не працює для класів завантаження, як у java.lang, java.util, ... Їх можна знайти, отримавши System.getProperty ("sun.boot.class.path"), розділившись з: або; (залежно від ОС), а потім запущені трохи змінені версії вищевказаних checkDirectory та checkJarFile.
coderforlife

1
Ви можете обійти попередження / помилку, використовуючи connection.getClass (). GetCanonicalName (). Equals ("sun.net.www.protocol.file.FileURLConnection"). Якщо ви дійсно хочете, ви можете створити URLConnection, який, на вашу думку, ДОЛЖЕН використовувати sun.net.www.protocol.file.FileURLConnection, а також порівняти ім'я класу з'єднання з назвою створеного вами класу. Якщо вони обидва однакові, ви можете розглядати це як екземпляр sun.net.www.protocol.file.FileURLCзв'язок, а не збій у разі зміни назви класу.
Вільям Дінс

1
@Christian Ви можете уникнути того, щоб FileURLConnection робив щось подібне: if ( ... instanceof JarURLConnecton) { ... } else { // Asume that the Connection is valid and points to a File }це я зробив у своєму коді для пошуку анотованих класів JPA
Zardoz89,

15

Без використання зайвих бібліотек:

package test;

import java.io.DataInputStream;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;

public class Test {
    public static void main(String[] args) throws Exception{
        List<Class> classes = getClasses(Test.class.getClassLoader(),"test");
        for(Class c:classes){
            System.out.println("Class: "+c);
        }
    }

    public static List<Class> getClasses(ClassLoader cl,String pack) throws Exception{

        String dottedPackage = pack.replaceAll("[/]", ".");
        List<Class> classes = new ArrayList<Class>();
        URL upackage = cl.getResource(pack);

        DataInputStream dis = new DataInputStream((InputStream) upackage.getContent());
        String line = null;
        while ((line = dis.readLine()) != null) {
            if(line.endsWith(".class")) {
               classes.add(Class.forName(dottedPackage+"."+line.substring(0,line.lastIndexOf('.'))));
            }
        }
        return classes;
    }
}

Коли я запускаю це в JAR, upackageце null... :(
Крістіан

Для пакету "com.mycompany.beans" замініть "тест" на "com / mycompany / beans"
James Jithin

4
Я отримую нуль при використанні цього коду. Здається, працює лише в тому випадку, якщо ваша банка є виконуваним
Алао

якщо ви отримали ім'я пакета від String pack = getPackage().getName();, тоді вам доведеться додатиpack = pack.replaceAll("[.]", "/");
user2682877

13

Взагалі завантажувачі класів не дозволяють сканувати всі класи на шляху. Але зазвичай єдиним використовуваним завантажувачем класів є UrlClassLoader, з якого ми можемо отримати список каталогів та файлів jar (див. GetURL ) та відкрити їх по черзі для переліку доступних класів. Такий підхід, який називається скануванням траєкторії класу, реалізований у програмі Scannotation and Reflections .

Reflections reflections = new Reflections("my.package");
Set<Class<? extends Object>> classes = reflections.getSubTypesOf(Object.class);

Інший підхід полягає у використанні Java Pluggable Annotation Processing API для написання процесора анотацій, який збиратиме всі анотовані класи під час компіляції та створює індексний файл для використання під час виконання. Цей механізм реалізований у бібліотеці ClassIndex :

// package-info.java
@IndexSubclasses
package my.package;

// your code
Iterable<Class> classes = ClassIndex.getPackageClasses("my.package");

Зауважте, що додаткові настройки не потрібні, оскільки сканування повністю автоматизоване завдяки компілятору Java автоматично виявляє будь-які процесори, знайдені на classpath.


це виявляє класи, упаковані в банку? Здається, це не працює для мене.
асгс

який інструмент ви намагаєтеся використовувати?
Sławek

Я використовую вкладку Reflections. Але я почав це працювати після додержання способу, згаданого @Aleksander Blomskøld для останніх версій цього лібу.
асгс

Привіт, я використовую eclipse і не можу змусити його працювати, ClassIndex.getPackageClasses ("мій.пакет") повертає порожню карту
Хуан

11

Найбільш надійний механізм для перерахування всіх класів у даному пакеті в даний час ClassGraph , оскільки він обробляє максимально широкий масив механізмів специфікації classpath , включаючи нову модульну систему JPMS. (Я автор.)

List<String> classNames = new ArrayList<>();
try (ScanResult scanResult = new ClassGraph().whitelistPackages("my.package")
        .enableClassInfo().scan()) {
    classNames.addAll(scanResult.getAllClasses().getNames());
}

5

Ось як я це роблю. Я сканую всі папки (підпакети) і не намагаюся завантажити анонімні класи:

   /**
   * Attempts to list all the classes in the specified package as determined
   * by the context class loader, recursively, avoiding anonymous classes
   * 
   * @param pckgname
   *            the package name to search
   * @return a list of classes that exist within that package
   * @throws ClassNotFoundException
   *             if something went wrong
   */
  private static List<Class> getClassesForPackage(String pckgname) throws ClassNotFoundException {
      // This will hold a list of directories matching the pckgname. There may be more than one if a package is split over multiple jars/paths
      ArrayList<File> directories = new ArrayList<File>();
      String packageToPath = pckgname.replace('.', '/');
      try {
          ClassLoader cld = Thread.currentThread().getContextClassLoader();
          if (cld == null) {
              throw new ClassNotFoundException("Can't get class loader.");
          }

          // Ask for all resources for the packageToPath
          Enumeration<URL> resources = cld.getResources(packageToPath);
          while (resources.hasMoreElements()) {
              directories.add(new File(URLDecoder.decode(resources.nextElement().getPath(), "UTF-8")));
          }
      } catch (NullPointerException x) {
          throw new ClassNotFoundException(pckgname + " does not appear to be a valid package (Null pointer exception)");
      } catch (UnsupportedEncodingException encex) {
          throw new ClassNotFoundException(pckgname + " does not appear to be a valid package (Unsupported encoding)");
      } catch (IOException ioex) {
          throw new ClassNotFoundException("IOException was thrown when trying to get all resources for " + pckgname);
      }

      ArrayList<Class> classes = new ArrayList<Class>();
      // For every directoryFile identified capture all the .class files
      while (!directories.isEmpty()){
          File directoryFile  = directories.remove(0);             
          if (directoryFile.exists()) {
              // Get the list of the files contained in the package
              File[] files = directoryFile.listFiles();

              for (File file : files) {
                  // we are only interested in .class files
                  if ((file.getName().endsWith(".class")) && (!file.getName().contains("$"))) {
                      // removes the .class extension
                      int index = directoryFile.getPath().indexOf(packageToPath);
                      String packagePrefix = directoryFile.getPath().substring(index).replace('/', '.');;                          
                    try {                  
                      String className = packagePrefix + '.' + file.getName().substring(0, file.getName().length() - 6);                            
                      classes.add(Class.forName(className));                                
                    } catch (NoClassDefFoundError e)
                    {
                      // do nothing. this class hasn't been found by the loader, and we don't care.
                    }
                  } else if (file.isDirectory()){ // If we got to a subdirectory
                      directories.add(new File(file.getPath()));                          
                  }
              }
          } else {
              throw new ClassNotFoundException(pckgname + " (" + directoryFile.getPath() + ") does not appear to be a valid package");
          }
      }
      return classes;
  }  

4

Я зібрав простий проект github, який вирішує цю проблему:

https://github.com/ddopson/java-class-enumerator

Він повинен працювати для BOTH-файлових класових маршрутів AND для jar-файлів.

Якщо після запуску проекту запустити "make", він надрукує це:

 Cleaning...
rm -rf build/
 Building...
javac -d build/classes src/pro/ddopson/ClassEnumerator.java src/test/ClassIShouldFindOne.java src/test/ClassIShouldFindTwo.java src/test/subpkg/ClassIShouldFindThree.java src/test/TestClassEnumeration.java
 Making JAR Files...
jar cf build/ClassEnumerator_test.jar -C build/classes/ . 
jar cf build/ClassEnumerator.jar -C build/classes/ pro
 Running Filesystem Classpath Test...
java -classpath build/classes test.TestClassEnumeration
ClassDiscovery: Package: 'test' becomes Resource: 'file:/Users/Dopson/work/other/java-class-enumeration/build/classes/test'
ClassDiscovery: Reading Directory '/Users/Dopson/work/other/java-class-enumeration/build/classes/test'
ClassDiscovery: FileName 'ClassIShouldFindOne.class'  =>  class 'test.ClassIShouldFindOne'
ClassDiscovery: FileName 'ClassIShouldFindTwo.class'  =>  class 'test.ClassIShouldFindTwo'
ClassDiscovery: FileName 'subpkg'  =>  class 'null'
ClassDiscovery: Reading Directory '/Users/Dopson/work/other/java-class-enumeration/build/classes/test/subpkg'
ClassDiscovery: FileName 'ClassIShouldFindThree.class'  =>  class 'test.subpkg.ClassIShouldFindThree'
ClassDiscovery: FileName 'TestClassEnumeration.class'  =>  class 'test.TestClassEnumeration'
 Running JAR Classpath Test...
java -classpath build/ClassEnumerator_test.jar  test.TestClassEnumeration
ClassDiscovery: Package: 'test' becomes Resource: 'jar:file:/Users/Dopson/work/other/java-class-enumeration/build/ClassEnumerator_test.jar!/test'
ClassDiscovery: Reading JAR file: '/Users/Dopson/work/other/java-class-enumeration/build/ClassEnumerator_test.jar'
ClassDiscovery: JarEntry 'META-INF/'  =>  class 'null'
ClassDiscovery: JarEntry 'META-INF/MANIFEST.MF'  =>  class 'null'
ClassDiscovery: JarEntry 'pro/'  =>  class 'null'
ClassDiscovery: JarEntry 'pro/ddopson/'  =>  class 'null'
ClassDiscovery: JarEntry 'pro/ddopson/ClassEnumerator.class'  =>  class 'null'
ClassDiscovery: JarEntry 'test/'  =>  class 'null'
ClassDiscovery: JarEntry 'test/ClassIShouldFindOne.class'  =>  class 'test.ClassIShouldFindOne'
ClassDiscovery: JarEntry 'test/ClassIShouldFindTwo.class'  =>  class 'test.ClassIShouldFindTwo'
ClassDiscovery: JarEntry 'test/subpkg/'  =>  class 'null'
ClassDiscovery: JarEntry 'test/subpkg/ClassIShouldFindThree.class'  =>  class 'test.subpkg.ClassIShouldFindThree'
ClassDiscovery: JarEntry 'test/TestClassEnumeration.class'  =>  class 'test.TestClassEnumeration'
 Tests Passed. 

Дивіться також мою іншу відповідь


4

Так, використовуючи декілька API, які ви можете, ось, як мені подобається це робити, зіткнувся з цією проблемою, яку я використовував в сплячому режимі, і мені довелося знайти класи, де зазначається певна анотація.

Зробіть для них спеціальну примітку, за допомогою якої ви будете позначати, які класи ви хочете взяти.

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface EntityToBeScanned {

}

Потім позначте свій клас таким чином

@EntityToBeScanned 
public MyClass{

}

Зробіть цей клас утиліти, який має такий спосіб

public class ClassScanner {

    public static Set<Class<?>> allFoundClassesAnnotatedWithEntityToBeScanned(){
        Reflections reflections = new Reflections(".*");
        Set<Class<?>> annotated = reflections.getTypesAnnotatedWith(EntityToBeScanned.class);
        return annotated;
    }

}

Зателефонуйте до методу allFoundClassesAnnotatedWithEntityToBeScanned (), щоб отримати набір класів.

Вам знадобляться мочки, наведені нижче

<!-- https://mvnrepository.com/artifact/com.google.guava/guava -->
    <dependency>
        <groupId>com.google.guava</groupId>
        <artifactId>guava</artifactId>
        <version>21.0</version>
    </dependency>
<!-- https://mvnrepository.com/artifact/org.javassist/javassist -->
<dependency>
    <groupId>org.javassist</groupId>
    <artifactId>javassist</artifactId>
    <version>3.22.0-CR1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.reflections/reflections -->
<dependency>
    <groupId>org.reflections</groupId>
    <artifactId>reflections</artifactId>
    <version>0.9.10</version>
</dependency>

3

Вам потрібно шукати кожен запис завантажувача класу на шляху до класу:

    String pkg = "org/apache/commons/lang";
    ClassLoader cl = ClassLoader.getSystemClassLoader();
    URL[] urls = ((URLClassLoader) cl).getURLs();
    for (URL url : urls) {
        System.out.println(url.getFile());
        File jar = new File(url.getFile());
        // ....
    }   

Якщо запис є каталогом, просто знайдіть у правому підкаталозі:

if (jar.isDirectory()) {
    File subdir = new File(jar, pkg);
    if (!subdir.exists())
        continue;
    File[] files = subdir.listFiles();
    for (File file : files) {
        if (!file.isFile())
            continue;
        if (file.getName().endsWith(".class"))
            System.out.println("Found class: "
                    + file.getName().substring(0,
                            file.getName().length() - 6));
    }
}   

Якщо запис є файлом, і він є jar, перегляньте його записи ZIP:

else {
    // try to open as ZIP
    try {
        ZipFile zip = new ZipFile(jar);
        for (Enumeration<? extends ZipEntry> entries = zip
                .entries(); entries.hasMoreElements();) {
            ZipEntry entry = entries.nextElement();
            String name = entry.getName();
            if (!name.startsWith(pkg))
                continue;
            name = name.substring(pkg.length() + 1);
            if (name.indexOf('/') < 0 && name.endsWith(".class"))
                System.out.println("Found class: "
                        + name.substring(0, name.length() - 6));
        }
    } catch (ZipException e) {
        System.out.println("Not a ZIP: " + e.getMessage());
    } catch (IOException e) {
        System.err.println(e.getMessage());
    }
}

Тепер, коли у вас є всі назви класів з пакетом, ви можете спробувати завантажити їх з відображенням та проаналізувати, чи це класи, чи інтерфейси тощо.


Що б ви ввели для пакету у файлі Jar?
Кайл Бріденстін

Цей приклад не буде проходити через підпакети. Можливо, це цікавить когось ... @ mr-tea Просто вкажіть пакет, який ви шукаєте. Я помістив це в проект, вказав тестовий пакет в рамках цього проекту, склав і упакував його і назвав приклад із головного методу JAR. Працював як шарм. :)
Крістіан

3

Я намагався використовувати бібліотеку Reflections, але виникли деякі проблеми з її використанням, і було занадто багато банок, які я повинен включати, просто щоб отримати класи на пакеті.

Я опублікую рішення, знайдене в цьому дублюючому запитанні: Як отримати всі назви класів у пакеті?

Відповідь була написана sp00m ; Я додав кілька виправлень, щоб він працював:

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.Enumeration;
import java.util.LinkedList;
import java.util.List;

public final class ClassFinder {

    private final static char DOT = '.';
    private final static char SLASH = '/';
    private final static String CLASS_SUFFIX = ".class";
    private final static String BAD_PACKAGE_ERROR = "Unable to get resources from path '%s'. Are you sure the given '%s' package exists?";

    public final static List<Class<?>> find(final String scannedPackage) {
        final ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
        final String scannedPath = scannedPackage.replace(DOT, SLASH);
        final Enumeration<URL> resources;
        try {
            resources = classLoader.getResources(scannedPath);
        } catch (IOException e) {
            throw new IllegalArgumentException(String.format(BAD_PACKAGE_ERROR, scannedPath, scannedPackage), e);
        }
        final List<Class<?>> classes = new LinkedList<Class<?>>();
        while (resources.hasMoreElements()) {
            final File file = new File(resources.nextElement().getFile());
            classes.addAll(find(file, scannedPackage));
        }
        return classes;
    }

    private final static List<Class<?>> find(final File file, final String scannedPackage) {
        final List<Class<?>> classes = new LinkedList<Class<?>>();
        if (file.isDirectory()) {
            for (File nestedFile : file.listFiles()) {
                classes.addAll(find(nestedFile, scannedPackage));
            }
        //File names with the $1, $2 holds the anonymous inner classes, we are not interested on them. 
        } else if (file.getName().endsWith(CLASS_SUFFIX) && !file.getName().contains("$")) {

            final int beginIndex = 0;
            final int endIndex = file.getName().length() - CLASS_SUFFIX.length();
            final String className = file.getName().substring(beginIndex, endIndex);
            try {
                final String resource = scannedPackage + DOT + className;
                classes.add(Class.forName(resource));
            } catch (ClassNotFoundException ignore) {
            }
        }
        return classes;
    }

}

Для його використання просто зателефонуйте методу find як sp00n, згаданому в цьому прикладі: я додав створення екземплярів класів, якщо це потрібно.

List<Class<?>> classes = ClassFinder.find("com.package");

ExcelReporting excelReporting;
for (Class<?> aClass : classes) {
    Constructor constructor = aClass.getConstructor();
    //Create an object of the class type
    constructor.newInstance();
    //...
}

3

Я щойно написав клас утиліти, він включає методи тестування, ви можете мати перевірку ~

IteratePackageUtil.java:

package eric.j2se.reflect;

import java.util.Set;

import org.reflections.Reflections;
import org.reflections.scanners.ResourcesScanner;
import org.reflections.scanners.SubTypesScanner;
import org.reflections.util.ClasspathHelper;
import org.reflections.util.ConfigurationBuilder;
import org.reflections.util.FilterBuilder;

/**
 * an util to iterate class in a package,
 * 
 * @author eric
 * @date Dec 10, 2013 12:36:46 AM
 */
public class IteratePackageUtil {
    /**
     * <p>
     * Get set of all class in a specified package recursively. this only support lib
     * </p>
     * <p>
     * class of sub package will be included, inner class will be included,
     * </p>
     * <p>
     * could load class that use the same classloader of current class, can't load system packages,
     * </p>
     * 
     * @param pkg
     *            path of a package
     * @return
     */
    public static Set<Class<? extends Object>> getClazzSet(String pkg) {
        // prepare reflection, include direct subclass of Object.class
        Reflections reflections = new Reflections(new ConfigurationBuilder().setScanners(new SubTypesScanner(false), new ResourcesScanner())
                .setUrls(ClasspathHelper.forClassLoader(ClasspathHelper.classLoaders(new ClassLoader[0])))
                .filterInputsBy(new FilterBuilder().includePackage(pkg)));

        return reflections.getSubTypesOf(Object.class);
    }

    public static void test() {
        String pkg = "org.apache.tomcat.util";

        Set<Class<? extends Object>> clazzSet = getClazzSet(pkg);
        for (Class<? extends Object> clazz : clazzSet) {
            System.out.println(clazz.getName());
        }
    }

    public static void main(String[] args) {
        test();
    }
}

3

Рішення Олександра Бломскольда не працювало для мене для параметризованих тестів @RunWith(Parameterized.class)при використанні Maven. Тести були названі правильно, а також там, де їх знайдено, але не виконано:

-------------------------------------------------------
T E S T S
-------------------------------------------------------
Running some.properly.named.test.run.with.maven.SomeTest
Tests run: 0, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.123 sec

Аналогічна проблема повідомляється тут .

У моєму випадку @Parameters- створення примірників кожного класу в пакеті. Тести спрацювали добре при локальному запуску в IDE. Однак під час запуску Maven немає класів, де їх не знайдено з рішенням Олександра Бломскольда.

Я зробив це з наступними знімками, які були натхнені коментарем Девіда Парссона щодо відповіді Олександра Бломсколда:

Reflections reflections = new Reflections(new ConfigurationBuilder()
            .setScanners(new SubTypesScanner(false /* don't exclude Object.class */), new ResourcesScanner())
            .addUrls(ClasspathHelper.forJavaClassPath()) 
            .filterInputsBy(new FilterBuilder()
            .include(FilterBuilder.prefix(basePackage))));

Set<Class<?>> subTypesOf = reflections.getSubTypesOf(Object.class);

3

Як що до цього:

public static List<Class<?>> getClassesForPackage(final String pkgName) throws IOException, URISyntaxException {
    final String pkgPath = pkgName.replace('.', '/');
    final URI pkg = Objects.requireNonNull(ClassLoader.getSystemClassLoader().getResource(pkgPath)).toURI();
    final ArrayList<Class<?>> allClasses = new ArrayList<Class<?>>();

    Path root;
    if (pkg.toString().startsWith("jar:")) {
        try {
            root = FileSystems.getFileSystem(pkg).getPath(pkgPath);
        } catch (final FileSystemNotFoundException e) {
            root = FileSystems.newFileSystem(pkg, Collections.emptyMap()).getPath(pkgPath);
        }
    } else {
        root = Paths.get(pkg);
    }

    final String extension = ".class";
    try (final Stream<Path> allPaths = Files.walk(root)) {
        allPaths.filter(Files::isRegularFile).forEach(file -> {
            try {
                final String path = file.toString().replace('/', '.');
                final String name = path.substring(path.indexOf(pkgName), path.length() - extension.length());
                allClasses.add(Class.forName(name));
            } catch (final ClassNotFoundException | StringIndexOutOfBoundsException ignored) {
            }
        });
    }
    return allClasses;
}

Потім ви можете перевантажити функцію:

public static List<Class<?>> getClassesForPackage(final Package pkg) throws IOException, URISyntaxException {
    return getClassesForPackage(pkg.getName());
}

Якщо вам потрібно перевірити це:

public static void main(final String[] argv) throws IOException, URISyntaxException {
    for (final Class<?> cls : getClassesForPackage("my.package")) {
        System.out.println(cls);
    }
    for (final Class<?> cls : getClassesForPackage(MyClass.class.getPackage())) {
        System.out.println(cls);
    }
}

Якщо ваш IDE не має помічника для імпорту:

import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.file.FileSystemNotFoundException;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.stream.Stream;

Це працює:

  • від вашого IDE

  • для файлу JAR

  • без зовнішніх залежностей


2

Майже всі відповіді або використовують, Reflectionsабо читають файли класу з файлової системи. Якщо ви спробуєте прочитати класи з файлової системи, ви можете отримати помилки під час упаковки програми як JAR або іншої. Крім того, ви не можете використовувати окрему бібліотеку для цієї мети.

Ось ще один підхід, який є чисто Java і не залежить від файлової системи.

import javax.tools.JavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.StandardLocation;
import javax.tools.ToolProvider;
import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;

public class PackageUtil {

    public static Collection<Class> getClasses(final String pack) throws Exception {
        final StandardJavaFileManager fileManager = ToolProvider.getSystemJavaCompiler().getStandardFileManager(null, null, null);
        return StreamSupport.stream(fileManager.list(StandardLocation.CLASS_PATH, pack, Collections.singleton(JavaFileObject.Kind.CLASS), false).spliterator(), false)
                .map(javaFileObject -> {
                    try {
                        final String[] split = javaFileObject.getName()
                                .replace(".class", "")
                                .replace(")", "")
                                .split(Pattern.quote(File.separator));

                        final String fullClassName = pack + "." + split[split.length - 1];
                        return Class.forName(fullClassName);
                    } catch (ClassNotFoundException e) {
                        throw new RuntimeException(e);
                    }

                })
                .collect(Collectors.toCollection(ArrayList::new));
    }
}

Java 8 не є обов'язковим . Ви можете використовувати для циклів замість потоків. І ви можете це протестувати так

public static void main(String[] args) throws Exception {
    final String pack = "java.nio.file"; // Or any other package
    PackageUtil.getClasses(pack).stream().forEach(System.out::println);
}

1
Це не дуже корисно через: для використання потрібен JDKToolProvider.getSystemJavaCompiler() , цей код не сканує вкладені пакети.
v.ladynev

Я не можу змусити його працювати з пакетом зовнішньої банки
Енріко Джурін

1

Якщо ви не використовуєте динамічних навантажувачів класів, ви можете шукати шлях і для кожного запису шукати каталог або файл JAR.


1

Варто згадати

Якщо ви хочете мати список усіх класів під деяким пакетом, ви можете скористатися Reflectionнаступним чином:

List<Class> myTypes = new ArrayList<>();

Reflections reflections = new Reflections("com.package");
for (String s : reflections.getStore().get(SubTypesScanner.class).values()) {
    myTypes.add(Class.forName(s));
}

Це створить список класів, які згодом ви зможете використовувати їх за своїм бажанням.


1

Це дуже можливо, але без додаткових бібліотек, як Reflectionsце важко ...
Це важко, оскільки у вас немає повного інструменту для отримання імені класу.
І я беру код свого ClassFinderкласу:

package play.util;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

/**
 * Created by LINKOR on 26.05.2017 in 15:12.
 * Date: 2017.05.26
 */
public class FileClassFinder {
private JarFile file;
private boolean trouble;
public FileClassFinder(String filePath) {
    try {
        file = new JarFile(filePath);
    } catch (IOException e) {
        trouble = true;
    }
}

public List<String> findClasses(String pkg) {
    ArrayList<String> classes = new ArrayList<>();
    Enumeration<JarEntry> entries = file.entries();
    while (entries.hasMoreElements()) {
        JarEntry cls = entries.nextElement();
        if (!cls.isDirectory()) {
            String fileName = cls.getName();
            String className = fileName.replaceAll("/",         ".").replaceAll(File.pathSeparator, ".").substring(0, fileName.lastIndexOf('.'));
            if (className.startsWith(pkg)) classes.add(className.substring(pkg.length() + 1));
        }
    }
    return classes;
}
}

0

На основі відповіді @ Staale і намагаючись не покладатися на сторонні бібліотеки, я застосував би підхід файлової системи, перевіривши фізичне розташування першого пакета за допомогою:

import java.io.File;
import java.io.FileFilter;
import java.util.ArrayList;
...
Class<?>[] foundClasses = new Class<?>[0];
final ArrayList<Class<?>> foundClassesDyn = new ArrayList<Class<?>>();

new java.io.File(
    klass.getResource(
        "/" + curPackage.replace( "." , "/")
    ).getFile()
).listFiles(
    new java.io.FileFilter() {
        public boolean accept(java.io.File file) {
            final String classExtension = ".class";

            if ( file.isFile()
                && file.getName().endsWith(classExtension)
                // avoid inner classes
                && ! file.getName().contains("$") )
            {
                try {
                    String className = file.getName();
                    className = className.substring(0, className.length() - classExtension.length());
                    foundClassesDyn.add( Class.forName( curPackage + "." + className ) );
                } catch (ClassNotFoundException e) {
                    e.printStackTrace(System.out);
                }
            }

            return false;
        }
    }
);

foundClasses = foundClassesDyn.toArray(foundClasses);

0

Якщо ви просто хочете завантажити групу пов’язаних класів, тоді Весна може вам допомогти.

Spring може створити список або карту всіх класів, які реалізують даний інтерфейс в одному рядку коду. Список або карта міститимуть екземпляри всіх класів, які реалізують цей інтерфейс.

Це було сказано, як альтернатива завантаженню списку класів з файлової системи, натомість просто реалізуйте один і той же інтерфейс у всіх класах, які ви хочете завантажити, незалежно від пакету та використовуйте Spring для надання вам примірників усіх них. Таким чином, ви можете завантажити (та інстанціювати) всі потрібні вам класи, незалежно від того, в якому пакеті вони є.

З іншого боку, якщо їх все в пакеті - це те, що ви хочете, тоді просто всі класи в цьому пакеті реалізують заданий інтерфейс.


0

звичайна Java: FindAllClassesUsingPlainJavaReflectionTest.java

@Slf4j
class FindAllClassesUsingPlainJavaReflectionTest {

  private static final Function<Throwable, RuntimeException> asRuntimeException = throwable -> {
    log.error(throwable.getLocalizedMessage());
    return new RuntimeException(throwable);
  };

  private static final Function<String, Collection<Class<?>>> findAllPackageClasses = basePackageName -> {

    Locale locale = Locale.getDefault();
    Charset charset = StandardCharsets.UTF_8;
    val fileManager = ToolProvider.getSystemJavaCompiler()
                                  .getStandardFileManager(/* diagnosticListener */ null, locale, charset);

    StandardLocation location = StandardLocation.CLASS_PATH;
    JavaFileObject.Kind kind = JavaFileObject.Kind.CLASS;
    Set<JavaFileObject.Kind> kinds = Collections.singleton(kind);
    val javaFileObjects = Try.of(() -> fileManager.list(location, basePackageName, kinds, /* recurse */ true))
                             .getOrElseThrow(asRuntimeException);

    String pathToPackageAndClass = basePackageName.replace(".", File.separator);
    Function<String, String> mapToClassName = s -> {
      String prefix = Arrays.stream(s.split(pathToPackageAndClass))
                            .findFirst()
                            .orElse("");
      return s.replaceFirst(prefix, "")
              .replaceAll(File.separator, ".");
    };

    return StreamSupport.stream(javaFileObjects.spliterator(), /* parallel */ true)
                        .filter(javaFileObject -> javaFileObject.getKind().equals(kind))
                        .map(FileObject::getName)
                        .map(fileObjectName -> fileObjectName.replace(".class", ""))
                        .map(mapToClassName)
                        .map(className -> Try.of(() -> Class.forName(className))
                                             .getOrElseThrow(asRuntimeException))
                        .collect(Collectors.toList());
  };

  @Test
  @DisplayName("should get classes recursively in given package")
  void test() {
    Collection<Class<?>> classes = findAllPackageClasses.apply(getClass().getPackage().getName());
    assertThat(classes).hasSizeGreaterThan(4);
    classes.stream().map(String::valueOf).forEach(log::info);
  }
}

PS: для спрощення котлів для обробки помилок тощо, я тут використовую vavrі lombokбібліотеки

інші реабілітації можна знайти в моєму регрес-дагероку / java-роздумі-пошуку-анотованих класах-або-методах GitHub


0

Я не міг знайти короткий робочий фрагмент для чогось такого простого. Так ось, я це зробив сам, накрутившись на деякий час:

    Reflections reflections =
        new Reflections(new ConfigurationBuilder()
                .filterInputsBy(new FilterBuilder().includePackage(packagePath))
                .setUrls(ClasspathHelper.forPackage(packagePath))
                .setScanners(new SubTypesScanner(false)));

    Set<String> typeList = reflections.getAllTypes(); 

0

Якщо ви перебуваєте у Spring-Land, ви можете користуватися PathMatchingResourcePatternResolver;

  PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
  Resource[] resources = resolver.getResources("classpath*:some/package/name/*.class");

    Arrays.asList(resources).forEach(r->{
        ...
    });

-4

Це неможливо, оскільки всі класи в пакеті можуть бути не завантажені, тоді як ви завжди знаєте пакет класу.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.