Самоанализ пакета Java

Как я могу получить все классы в пакете?

6 ответов

Ты не можешь Классы могут входить через разные загрузчики классов, в том числе удаленные.

Вот более полный способ решить эту проблему для банок, основанный на идее, опубликованной JG.

/**
 * Scans all classloaders for the current thread for loaded jars, and then scans
 * each jar for the package name in question, listing all classes directly under
 * the package name in question. Assumes directory structure in jar file and class
 * package naming follow java conventions (i.e. com.example.test.MyTest would be in
 * /com/example/test/MyTest.class)
 */
public Collection<Class> getClassesForPackage(String packageName) throws Exception {
  String packagePath = packageName.replace(".", "/");
  ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
  Set<URL> jarUrls = new HashSet<URL>();

  while (classLoader != null) {
    if (classLoader instanceof URLClassLoader)
      for (URL url : ((URLClassLoader) classLoader).getURLs())
        if (url.getFile().endsWith(".jar")  // may want better way to detect jar files
          jarUrls.add(url);

    classLoader = classLoader.getParent();
  }

  Set<Class> classes = new HashSet<Class>();

  for (URL url : jarUrls) {
    JarInputStream stream = new JarInputStream(url.openStream()); // may want better way to open url connections
    JarEntry entry = stream.getNextJarEntry();

    while (entry != null) {
      String name = entry.getName();
      int i = name.lastIndexOf("/");

      if (i > 0 && name.endsWith(".class") && name.substring(0, i).equals(packagePath)) 
        classes.add(Class.forName(name.substring(0, name.length() - 6).replace("/", ".")));

      entry = stream.getNextJarEntry();
    }

    stream.close();
  }

  return classes;
}

Отсюда есть фрагмент, который делает именно то, что вы хотите, при условии, что классы можно найти локально:

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

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

У Java нет открытий.

Большинство продуктов, которые имеют возможность добавлять (открывать) новые классы, имеют либо текстовый файл, описывающий "Расширения программы", либо определенный каталог, в который можно поместить классы или файлы jar, использующие описанный трюк, такой как @JG. (Это то, что делает eclipse и рекомендуется для любого решения, где пользователь может добавить новый модуль вручную)

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

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

Другие вопросы по тегам