Получение всех Java классов из ClassPath
Уже не первый раз наталкиваюсь на достаточно общую задачу: найти все классы в classpath приложения. Каждый раз гуглю, пишу код, а потом он где-то теряется. Поэтому, выкладываю код своего решения, может быть кому-нибудь пригодится. А если не пригодится напрямую, здесь видно как читать Jar-файлы))) Короче, говоря, гугл рассудит) Краткое описание подхода, чтобы лучше понимался код:- Разделяем строку classpath на записи, ссылающиеся на конкретные директории и jar-файлы. В линуксе разделитель между ними - двоеточие, в винде - точка с запятой. Дальше, для каждой записи:
- Если запись ссылается на директорию - рекурсивно сканируем ее, считая директорию, откуда начали сканирование соответствующей корневому пакету.
- Если запись ссылается на файл, пытаемся анализировать его как Jar-файл, используя инструментарий из пакета java.util.jar
Итак, код:
package ru.infoconnect.utils.classes;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Enumeration;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
public class ClassPathScanner {
/**
* Просканировать строку, представляющую из себя classpath и вернуть
* коллекцию найденных классов
*
* @param cp
* classpath
* @return коллекция обнаруженных классов
* @throws IOException
*/
public static Collection<String> scan( String cp ) throws IOException {
Collection<String> classes = new ArrayList<String>();
scan( cp, classes );
return classes;
}
/**
* Просканировать строку, представляющую из себя classpath и добавить все
* найденные классы в коллекцию
*
* @param cp
* classpath
* @param classes
* коллекция классов, в которую добавляются результаты
* @throws IOException
*/
public static void scan( String cp, Collection<String> classes ) throws IOException {
String[] entries = cp.split( File.pathSeparator );
for ( String entryName : entries ) {
File file = new File( entryName );
if ( file.isDirectory() ) {
scanDir( "", file, classes );
} else if ( file.getName().endsWith( ".jar" ) || file.getName().endsWith( ".zip" ) ) {
scanJar( file, classes );
} else {
throw new IOException( "Unknown classpath entry " + file.getName() );
}
}
}
/**
* Сканировать Jar-файл на предмет наличия class-файлов
*
* @param jarFile
* файл архива
* @param classes
* коллекция классов, в которую добавляются результаты
* @throws IOException
*/
private static void scanJar( File jarFile, Collection<String> classes ) throws IOException {
JarFile jar = new JarFile( jarFile ); // Открываем Jar-файл для чтения списка файлов
for ( Enumeration<JarEntry> e = jar.entries(); e.hasMoreElements(); ) {
JarEntry entry = e.nextElement();
if ( entry.isDirectory() ) // Попускаем директории
continue;
scanFileName( entry.getName(), classes ); // Если элемент - файл, проверяем его имя
}
jar.close();
}
/**
* Сканировать директорию, представляющую пакет на предмет наличия
* class-файлов.
*
* @param pkg
* имя пакета
* @param dir
* директория
* @param classes
* коллекция классов, в которую добавляются результаты
*/
private static void scanDir( String pkg, File dir, Collection<String> classes ) {
for ( File file : dir.listFiles() ) { // Перебираем все файлы в директории
if ( file.isDirectory() ) {
scanDir( pkg + file.getName() + File.separator, file, classes ); // Сканируем директорию пакета
} else {
scanFileName( pkg + file.getName(), classes ); // Проверяем имя файла
}
}
}
/**
* Проверить имя файла и извлечь имя класса
*
* @param name
* имя файла
* @param classes
* коллекция классов, в которую добавляются результаты
*/
private static void scanFileName( String name, Collection<String> classes ) {
if ( !name.endsWith( ".class" ) )
return;
classes.add( name.substring( 0, name.length() - 6 ).replace( File.separator, '.' ) ); // Извлекаем имя класса из имени файла: удаляем расширение и преобразуем разделители
}
}

on July 24, 2009 at 14:07 Дмитрий Пекар wrote:
Знакомая техника. Иногда без этого обойтись трудно. Например, во всякого рода загрузчиках,
которые ищут все классы, реализующие "точку-входа".
on November 26, 2009 at 22:11 kyy wrote:
1. шкурный вопрос - лицензия? :) (я понимаю что код простой, но переписывать лень) Вышел на код из гугла, посему не уверен - может она где и указана...
2. Java 1.7: File.separator -> File.pathSeparatorChar
on November 26, 2009 at 22:11 Alno wrote:
1. Public Domain
2. Тогда уж так:
File.separator -> File.separatorChar
File.pathSeparator -> File.pathSeparatorChar
И разве в Java 1.7 соответствующие строковые константы убрали? Пока с ней не сталкивался просто...
on January 14, 2010 at 12:01 Gulya wrote:
Спасибо огромное! Очень помогли!