Можете ли вы найти все имена пакетов и классов в пути к классам проекта? [Дубликат]

Как насчет этого:

select all_fields.*  
from  (select id, MAX(rev) from yourtable group by id) as max_recs  
left outer join yourtable as all_fields  
on max_recs.id = all_fields.id
442
задан Willi Mentzel 29 June 2015 в 14:30
поделиться

21 ответ

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

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

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

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

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

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

 Set<Class<? extends Object>> allClasses = 
     reflections.getSubTypesOf(Object.class);
317
ответ дан Bogdan Mart 31 August 2018 в 11:02
поделиться

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

Сначала настройте индекс отражений (это немного беспорядочно, так как поиск по всем классам по умолчанию отключен):

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"))));

Then вы можете запросить все объекты в данном пакете:

Set<Class<?>> classes = reflections.getSubTypesOf(Object.class);
160
ответ дан Aleksander Blomskøld 31 August 2018 в 11:02
поделиться

Почти все ответы либо используют 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);
}
2
ответ дан bhdrkn 31 August 2018 в 11:02
поделиться

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

Следующий код - это в основном метод переполнения, который всегда будет работать.

Код:

Этот код сканирует данный пакет для всех классов, включенных в него. Он будет работать только для всех классов в текущем 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. Затем он извлекает все ресурсы, содержащие указанный пакет, и итерации этих URL s. Затем он создает URLConnection и определяет тип URl, который у нас есть. Это может быть либо каталог (FileURLConnection), либо каталог внутри jar или zip-файла (JarURLConnection). В зависимости от типа соединения мы будем вызывать два разных метода.

Сначала давайте посмотрим, что произойдет, если это FileURLConnection. Сначала он проверяет, существует ли переданный файл и является ли он каталогом. Если это так, он проверяет, является ли это файлом класса. Если это так, то объект Class будет создан и помещен в ArrayList. Если это не файл класса, а каталог, мы просто повторяем его и делаем то же самое. Все остальные случаи / файлы будут игнорироваться.

Если URLConnection является JarURLConnection, будет вызван другой метод private helper. Этот метод выполняет итерацию по всем записям в архиве zip / jar. Если одна запись является файлом класса и находится внутри пакета, объект Class будет создан и сохранен в ArrayList.

После того, как все ресурсы были проанализированы, он (основной метод) возвращает ArrayList содержит все классы в данном пакете, о которых знает текущий ClassLoader.

Если процесс завершается с ошибкой в ​​любой момент, а ClassNotFoundException будет зависеть от подробной информации о конкретной причине.

29
ответ дан BrainStone 31 August 2018 в 11:02
поделиться

Без использования каких-либо дополнительных библиотек:

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;
    }
}
12
ответ дан Christian 31 August 2018 в 11:02
поделиться

На основании ответа @ 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);
4
ответ дан Community 31 August 2018 в 11:02
поделиться

Вам нужно просмотреть каждую запись загрузчика класса в пути к классу:

    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());
    }
}

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

3
ответ дан Danubian Sailor 31 August 2018 в 11:02
поделиться

Я только что написал класс util, включая методы тестирования, вы можете проверить ~

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();
    }
}
1
ответ дан Eric Wang 31 August 2018 в 11:02
поделиться

Вы можете использовать этот метод 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: // фрагментов. dzone.com/posts/show/4831, который был архивирован через Интернет-архив, связанный с ним сейчас. Фрагмент также доступен в https://dzone.com/articles/get-all-classes-within-package .

86
ответ дан Just a student 31 August 2018 в 11:02
поделиться

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

1
ответ дан Lawrence Dol 31 August 2018 в 11:02
поделиться

Я решил FastClasspathScanner решить эту проблему. Он обрабатывает много разных типов задач сканирования классов, имеет простой API, работает со многими различными классами ClassLoaders и classpath, тщательно распараллелен и оптимизирован для высокоскоростного и низкого потребления памяти. Он может даже генерировать визуализацию GraphViz графа классов, показывая, как классы связаны друг с другом.

Для вашего первоначального вопроса о поиске всех классов или интерфейсов в данном пакете вы можете сделать:

List<String> classNames = new FastClasspathScanner("com.mypackage").scan()
    .getNamesOfAllClasses();

Существует много возможных вариантов: см. документацию (см. выше) для полной информации.

6
ответ дан Luke Hutchison 31 August 2018 в 11:02
поделиться

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

-3
ответ дан Marko 31 August 2018 в 11:02
поделиться

Стоит упомянуть

Если вы хотите иметь список всех классов под некоторым пакетом, вы можете использовать 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));
}

Это создаст список классов, которые позже вы можете использовать их по своему усмотрению.

2
ответ дан Maroun 31 August 2018 в 11:02
поделиться

Это очень возможно, но без дополнительных библиотек, таких как 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;
}
}
1
ответ дан Muskovets 31 August 2018 в 11:02
поделиться

Вот как я это делаю. Я сканирую все подпапки (подпакеты), и я не пытаюсь загружать анонимные классы:

   /**
   * 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;
  }  
5
ответ дан Nadav B 31 August 2018 в 11:02
поделиться

Google Guava 14 включает новый класс ClassPath с тремя методами сканирования для классов верхнего уровня:

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

Подробнее см. в ClassPath javadocs .

104
ответ дан rcreswick 31 August 2018 в 11:02
поделиться

Если вы просто хотите загрузить группу связанных классов, Spring может вам помочь.

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

Как говорится, в качестве альтернативы загрузке списка классов из файловой системы вместо этого нужно реализовать один и тот же интерфейс во всех классы, которые вы хотите загрузить, независимо от пакета и использовать Spring, чтобы предоставить вам все экземпляры. Таким образом, вы можете загружать (и создавать экземпляры) все классы, которые вы хотите, независимо от того, в каком пакете они находятся.

С другой стороны, если наличие всех в пакете - это то, что вы хотите, все классы в этом пакете реализуют данный интерфейс.

0
ответ дан Rodney P. Barbati 31 August 2018 в 11:02
поделиться

Да, используя несколько API, вы можете, вот как мне нравится это делать, столкнулись с этой проблемой, с которой я использовал hibernate core & amp; должен был найти классы, в которых аннотируется определенная аннотация.

Сделайте эти пользовательские аннотации, используя которые вы отметите, какие классы вы хотите получить.

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 (), чтобы получить набор найденных классов.

Вам понадобятся libs, приведенные ниже

<!-- 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>
4
ответ дан Sujal Mandal 31 August 2018 в 11:02
поделиться

В обычных загрузчиках классов не разрешено сканирование всех классов в пути к классам. Но обычно единственным используемым загрузчиком классов является UrlClassLoader, из которого мы можем получить список каталогов и файлов jar (см. getURLs ) и открывать их один за другим для отображения доступных классов. Этот подход, называемый сканированием пути к классу, реализован в Scannotation и Reflections .

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

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

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

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

Обратите внимание, что никакая дополнительная настройка не требуется, поскольку сканирование полностью автоматизировано благодаря компилятору Java, автоматически обнаруживающему любые процессоры, найденные в пути к классам .

10
ответ дан Sławek 31 August 2018 в 11:02
поделиться

Решение Александра Бломскёльда не работало для меня для параметризованных тестов @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

В этом случае ] создает экземпляры каждого класса в пакете. Тесты хорошо работали при локальном запуске в среде 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);
2
ответ дан Thorsten 31 August 2018 в 11:02
поделиться

Spring

Этот пример относится к 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
  }
}
75
ответ дан voho 31 August 2018 в 11:02
поделиться
Другие вопросы по тегам:

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