Как мне прочитать все классы из пакета Java в classpath? - PullRequest
90 голосов
/ 22 сентября 2009

Мне нужно прочитать классы, содержащиеся в пакете Java. Эти классы находятся в classpath. Мне нужно сделать эту задачу непосредственно из программы Java. Знаете ли вы простой способ сделать?

List<Class> classes = readClassesFrom("my.package")

Ответы [ 17 ]

47 голосов
/ 17 марта 2011

Если у вас есть Spring в вашем classpath, то следующее сделает это.

Найти все классы в пакете, аннотированные XmlRootElement:

private List<Class> findMyTypes(String basePackage) throws IOException, ClassNotFoundException
{
    ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
    MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory(resourcePatternResolver);

    List<Class> candidates = new ArrayList<Class>();
    String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
                               resolveBasePackage(basePackage) + "/" + "**/*.class";
    Resource[] resources = resourcePatternResolver.getResources(packageSearchPath);
    for (Resource resource : resources) {
        if (resource.isReadable()) {
            MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(resource);
            if (isCandidate(metadataReader)) {
                candidates.add(Class.forName(metadataReader.getClassMetadata().getClassName()));
            }
        }
    }
    return candidates;
}

private String resolveBasePackage(String basePackage) {
    return ClassUtils.convertClassNameToResourcePath(SystemPropertyUtils.resolvePlaceholders(basePackage));
}

private boolean isCandidate(MetadataReader metadataReader) throws ClassNotFoundException
{
    try {
        Class c = Class.forName(metadataReader.getClassMetadata().getClassName());
        if (c.getAnnotation(XmlRootElement.class) != null) {
            return true;
        }
    }
    catch(Throwable e){
    }
    return false;
}
29 голосов
/ 23 октября 2011

Вы можете использовать проект отражений, описанный здесь

Это довольно полный и простой в использовании.

Краткое описание с вышеуказанного сайта:

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

Пример:

Reflections reflections = new Reflections(
    new ConfigurationBuilder()
        .setUrls(ClasspathHelper.forJavaClassPath())
);
Set<Class<?>> types = reflections.getTypesAnnotatedWith(Scannable.class);
26 голосов
/ 18 сентября 2011

Я использую этот, он работает с файлами или архивами jar

public static ArrayList<String>getClassNamesFromPackage(String packageName) throws IOException{
    ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
    URL packageURL;
    ArrayList<String> names = new ArrayList<String>();;

    packageName = packageName.replace(".", "/");
    packageURL = classLoader.getResource(packageName);

    if(packageURL.getProtocol().equals("jar")){
        String jarFileName;
        JarFile jf ;
        Enumeration<JarEntry> jarEntries;
        String entryName;

        // build jar file name, then loop through zipped entries
        jarFileName = URLDecoder.decode(packageURL.getFile(), "UTF-8");
        jarFileName = jarFileName.substring(5,jarFileName.indexOf("!"));
        System.out.println(">"+jarFileName);
        jf = new JarFile(jarFileName);
        jarEntries = jf.entries();
        while(jarEntries.hasMoreElements()){
            entryName = jarEntries.nextElement().getName();
            if(entryName.startsWith(packageName) && entryName.length()>packageName.length()+5){
                entryName = entryName.substring(packageName.length(),entryName.lastIndexOf('.'));
                names.add(entryName);
            }
        }

    // loop through files in classpath
    }else{
    URI uri = new URI(packageURL.toString());
    File folder = new File(uri.getPath());
        // won't work with path which contains blank (%20)
        // File folder = new File(packageURL.getFile()); 
        File[] contenuti = folder.listFiles();
        String entryName;
        for(File actual: contenuti){
            entryName = actual.getName();
            entryName = entryName.substring(0, entryName.lastIndexOf('.'));
            names.add(entryName);
        }
    }
    return names;
}
11 голосов
/ 03 сентября 2010

Spring реализовал отличную функцию поиска по пути к классам в PathMatchingResourcePatternResolver. Если вы используете префикс classpath*:, вы можете найти все ресурсы, включая классы в данной иерархии, и даже отфильтровать их, если хотите. Затем вы можете использовать дочерние элементы AbstractTypeHierarchyTraversingFilter, AnnotationTypeFilter и AssignableTypeFilter для фильтрации этих ресурсов либо по аннотациям на уровне класса, либо по интерфейсам, которые они реализуют.

6 голосов
/ 10 марта 2012

Scannotation и Reflections использовать подход сканирования пути класса:

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

Другой подход заключается в использовании API обработки аннотаций Pluggable Java для написания процессора аннотаций, который будет собирать все аннотированные классы во время компиляции и создания файла индекса для использования во время выполнения. Этот механизм реализован в библиотеке ClassIndex :

Iterable<Class> classes = ClassIndex.getPackageClasses("my.package");
6 голосов
/ 19 марта 2011

Java 1.6.0_24:

public static File[] getPackageContent(String packageName) throws IOException{
    ArrayList<File> list = new ArrayList<File>();
    Enumeration<URL> urls = Thread.currentThread().getContextClassLoader()
                            .getResources(packageName);
    while (urls.hasMoreElements()) {
        URL url = urls.nextElement();
        File dir = new File(url.getFile());
        for (File f : dir.listFiles()) {
            list.add(f);
        }
    }
    return list.toArray(new File[]{});
}

Это решение было протестировано в среде EJB .

3 голосов
/ 22 сентября 2009

Насколько я знаю, эта функциональность все еще подозрительно отсутствует в API отражения Java. Вы можете получить объект пакета, просто выполнив это:

Package packageObj = Package.getPackage("my.package");

Но, как вы, наверное, заметили, это не позволит вам перечислить классы в этом пакете. На данный момент вы должны использовать более ориентированный на файловую систему подход.

Я нашел несколько примеров реализации в этом посте

Я не уверен на 100%, что эти методы будут работать, когда ваши классы зарыты в файлы JAR, но я надеюсь, что один из них сделает это за вас.

Я согласен с @skaffman ... если у вас есть другой способ сделать это, я бы рекомендовал сделать это вместо этого.

3 голосов
/ 24 сентября 2015

Вы можете попробовать мою библиотеку FastClasspathScanner . Сканирование пути к классам не так просто, как проверка свойства java.class.path и рекурсивное сканирование классов там, потому что существует множество способов указания пути к классам (например, вы можете добавить Class-Path записей в манифест jarfile). Использование Class.forName () фактически инициализирует класс, что может быть не тем, что вам нужно, и т. Д. FastClasspathScanner обрабатывает эти сложности за вас.

Чтобы перечислить все классы в пакете, выполните следующие действия:

String packageName = "my.package";
Set<String> classNames = new FastClassPathScanner(packageName)
    .scan()
    .getNamesOfAllClasses();
String packageNamePrefix = packageName + ".";
for (String className : classNames) {
    if (className.startsWith(packageNamePrefix) {
        System.out.println("Found class: " + className);
   }
}

Вам нужна проверка if (className.startsWith(packageNamePrefix), потому что если класс ссылается на другой класс (например, как суперкласс), и он находится вне префикса пакета из белого списка my.package, он будет включен в набор, возвращаемый .getNamesOfAllClasses().

2 голосов
/ 13 декабря 2011

eXtcos выглядит многообещающе. Представьте, что вы хотите найти все классы, которые:

  1. Расширение от класса "Компонент" и сохранение их
  2. помечены как "MyComponent", а
  3. В «обычной» упаковке.

С eXtcos это так же просто, как

ClasspathScanner scanner = new ClasspathScanner();
final Set<Class> classStore = new ArraySet<Class>();

Set<Class> classes = scanner.getClasses(new ClassQuery() {
    protected void query() {
        select().
        from(“common”).
        andStore(thoseExtending(Component.class).into(classStore)).
        returning(allAnnotatedWith(MyComponent.class));
    }
});
2 голосов
/ 22 июля 2011
  1. Билл Берк написал (хорошая статья о сканировании классов), а затем написал Scannotation .

  2. Hibernate это уже написано:

    • org.hibernate.ejb.packaging.Scanner
    • org.hibernate.ejb.packaging.NativeScanner
  3. CDI может решить эту проблему, но не знаю - еще не исследовал полностью

.

@Inject Instance< MyClass> x;
...
x.iterator() 

Также для аннотаций:

abstract class MyAnnotationQualifier
extends AnnotationLiteral<Entity> implements Entity {}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...