Java: программно определить все имена пакетов, загруженных в classpath - PullRequest
10 голосов
/ 18 ноября 2010

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

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


Подробнее:

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

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

Бонусные баллы

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

Спасибо!

Ответы [ 3 ]

6 голосов
/ 18 ноября 2010

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

EDIT #1: Вы можете получить classpath следующим образом (из примера здесь ):

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

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

РЕДАКТИРОВАТЬ # 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 );
                }
            }
        }
    }
}
3 голосов
/ 18 ноября 2010

Дайте http://code.google.com/p/reflections/ выстрел.

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

2 голосов
/ 18 ноября 2010

Этот код даст вам все записи 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-), посещение всех подкаталогов (рекурсивно), и если (и только если) каталог содержит хотя бы один файл класса, имя этого каталога (относительно записи classpath ) можно преобразовать в имя пакета (пример: META_INF - это каталог во всех jar-файлах, но не имя пакета ...)

...