Можете ли вы найти все классы в пакете, используя отражение?

Вот что вы имеете в виду:

var menuItem49 = $('#menu-item-49');
if (menuItem49.hasClass('current-menu-item') || menuItem49.hasClass('current-menu-parent')) {
    // ...
}
488
задан Willi Mentzel 29 June 2015 в 14:30
поделиться

6 ответов

Из-за динамического характера загрузчиков класса, это не возможно. Загрузчики класса не требуются, чтобы говорить VM, какие классы это может обеспечить, вместо этого им просто вручают запросы на классы, и должны возвратить класс или выдать исключение.

Однако, если Вы пишете свои собственные загрузчики класса или исследуете пути к классам и это - банки, возможно найти эту информацию. Это будет через операции файловой системы хотя, и не отражение. Могли бы даже быть библиотеки, которые могут помочь Вам сделать это.

, Если существуют классы, которые сгенерированы, или поставил удаленно, Вы не сможете обнаружить те классы.

нормальный метод должен вместо этого где-нибудь зарегистрировать классы, к которым Вы нуждаетесь в доступе в файле или ссылаетесь на них в другом классе. Или просто используйте конвенцию когда дело доходит до именования.

Приложение: Библиотека Отражений позволит Вам искать классы в текущем пути к классу. Это может использоваться для получения всех классов в пакете:

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

 Set<Class<? extends Object>> allClasses = 
     reflections.getSubTypesOf(Object.class);
355
ответ дан Bogdan Mart 30 June 2015 в 00:30
поделиться

Вы могли использовать этот метод <глоток> 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.

104
ответ дан Ahmed Ashour 30 June 2015 в 00:30
поделиться

Это не возможно, так как все классы в пакете не могли бы быть загружены, в то время как Вы всегда знаете пакет класса.

-3
ответ дан Marko 30 June 2015 в 00:30
поделиться

Что относительно этого:

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 без внешних зависимостей

0
ответ дан 22 November 2019 в 22:36
поделиться

Я не мог найти короткую работу отрезанной для чего-то настолько простого. Таким образом, здесь это, я сделал его сам после валяния дурака некоторое время:

    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
ответ дан 22 November 2019 в 22:36
поделиться

При условии, что вы не используете какие-либо динамические загрузчики классов, вы можете выполнять поиск по пути к классам и для каждой записи искать в каталоге или файле JAR.

1
ответ дан 22 November 2019 в 22:36
поделиться
Другие вопросы по тегам:

Похожие вопросы: