Подтвердить что ты не робот

Java: программно определить все имена пакетов, загруженные в путь к классам

Любые предложения относительно того, как подойти, как я узнаю список имен пакетов, которые существуют в текущем пути к классам?

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


Подробнее:

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

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

Бонусные очки

Бонусные баллы для всех, кто предлагает способ, который может фильтровать пакеты верхнего уровня. Например. показать все пакеты под com.xyz == > com.xyz.*, com.xyz.*.*

Спасибо!

4b9b3361

Ответ 1

Если вам нужно монтировать и сканировать файлы jar, commons-vfs имеет встроенный встроенный файл. Это может сделать вещи немного легче, если у вас есть идти по этому маршруту.

РЕДАКТИРОВАТЬ № 1: вы можете получить такой путь к классам (из примера здесь):

String strClassPath = System.getProperty("java.class.path");
System.out.println("Classpath is " + strClassPath);

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

EDIT # 2: Вот решение с VFS:

import java.util.HashSet;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.vfs.FileObject;
import org.apache.commons.vfs.FileSystemManager;
import org.apache.commons.vfs.FileType;
import org.apache.commons.vfs.VFS;

public class PackageLister {

    private static HashSet< String > packageNames = new HashSet< String >();
    private static String localFilePath;

    /**
     * @param args
     * @throws Throwable
     */
    public static void main( final String[] args ) throws Throwable {
        FileSystemManager fileSystemManager = VFS.getManager();

        String[] pathElements = System.getProperty( "java.class.path" ).split( ";" );
        for( String element : pathElements ) {
            if ( element.endsWith( "jar" ) ) {
                FileObject fileObject = fileSystemManager.resolveFile( "jar://" + element );
                addPackages( fileObject );
            }
            else {
                FileObject fileObject = fileSystemManager.resolveFile( element );
                localFilePath = fileObject.getName().getPath();

                addPackages( fileObject );
            }
        }

        for( String name : packageNames ) {
            System.out.println( name );
        }
    }

    private static void addPackages( final FileObject fileObject ) throws Throwable {
        FileObject[] children = fileObject.getChildren();
        for( FileObject child : children ) {
            if ( !child.getName().getBaseName().equals( "META-INF" ) ) {
                if ( child.getType() == FileType.FOLDER ) {
                    addPackages( child );
                }
                else if ( child.getName().getExtension().equals( "class" ) ) {
                    String parentPath = child.getParent().getName().getPath();
                    parentPath = StringUtils.remove( parentPath, localFilePath );
                    parentPath = StringUtils.removeStart( parentPath, "/" );
                    parentPath = parentPath.replaceAll( "/", "." );

                    packageNames.add( parentPath );
                }
            }
        }
    }
}

Ответ 2

Дайте http://code.google.com/p/reflections/ снимок.

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

Ответ 3

Этот код предоставит вам все записи classpath (включая библиотеки jre):

String[] entries = ClassPath.getClassPath().split(";");
for (String entry:entries)
  System.out.println(entry);

ClassPath является частью apache bcel и может быть найден как внутренний (но используемый) класс в jre (com.sun.org.apache.bcel.internal.util). AFAIK, класс является "внутренним", чтобы избежать конфликтов, когда проект требует "реальной" библиотеки bcel.

Вы можете фильтровать библиотеки JRE (они включены, поскольку это реальный путь к классам)

Следующий шаг будет смотреть на каждую запись (JarFile-), посещать все подкаталоги (рекурсивно), и если (и только если) в каталоге содержится хотя бы один файл класса, имя этого каталога (относительно записи пути к классу ) можно преобразовать в имя пакета (пример: META_INF - это каталог во всех файлах jar, но не имя пакета...)