Java: determina programaticamente todos os nomes de pacotes carregados no caminho de class

Alguma sugestão sobre como abordar como eu descobriria uma lista de nomes de pacotes que existem no caminho de class atual ?

Isso precisa ser feito programaticamente em tempo de execução por uma das classs carregadas (e executadas) no caminho de class (ou seja, dentro e fora , não fora).


Mais detalhes:

Uma abordagem que considerei foi usar a reflection em cada uma das classs carregadas até o momento pelo carregador de classs e extrair os nomes dos pacotes delas. No entanto, meu aplicativo já está em milhares de classs, por isso preciso de uma abordagem mais eficiente.

Outra coisa que considerei foi algo análogo ao descobrir quais arquivos JAR estavam no caminho da class e, em seguida, fazer o diretório listar em paralelo para cada JAR. No entanto, não sei se isso é possível de dentro do aplicativo / como fazê-lo.

Pontos bônus

Pontos de bônus para qualquer um que sugira uma maneira que possa filtrar por pacotes de nível superior. Por exemplo, mostre todos os pacotes que estão em com.xyz ==> com.xyz.* , com.xyz.*.*

Obrigado!

Se você precisa montar e escanear arquivos jar, o commons-vfs tem isso embutido. Isso pode tornar as coisas um pouco mais fáceis se você tiver que seguir esse caminho.

EDIT # 1: Você pode obter o classpath assim (a partir do exemplo aqui ):

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

De lá, você pode ver as classs, jarros, etc. do sistema de arquivos local.

EDIT # 2: Aqui está uma solução com o 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 ); } } } } } 

http://code.google.com/p/reflections/ uma foto.

O Reflections verifica seu caminho de class, indexa os metadados, permite consultá-lo em tempo de execução e pode salvar e coletar essas informações para muitos módulos em seu projeto.

Este código lhe dará todas as inputs do caminho de class (incluindo as bibliotecas do jre):

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

ClassPath é parte do apache bcel e pode ser encontrado como uma class interna (mas utilizável) no jre ( com.sun.org.apache.bcel.internal.util ). AFAIK, a class é “interna” para evitar conflitos quando um projeto requer a biblioteca bcel “real”.

Você pode querer filtrar as bibliotecas do JRE (elas estão incluídas, pois esse é o caminho de class real )

A próxima etapa seria examinar cada input (JarFile-), visitar todos os subdiretórios (recursivamente) e se (e somente se) um diretório contiver pelo menos um arquivo de class, o nome desse diretório (relativo à input do caminho de class) pode ser convertido em um nome de pacote (exemplo: META_INF é um diretório em todos os arquivos jar mas não um nome de pacote …)

Intereting Posts