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