Java:以编程方式确定类路径上加载的所有包名称

时间:2010-11-18 06:04:15

标签: java reflection jar classpath package

有关如何找到当前类路径上存在的包名称列表的建议?

这需要在运行时通过类路径上加载(和执行)的类之一以编程方式完成(即由内向外,而不是在外部)。


更多详情:

我考虑过的一种方法是对类加载器到目前为止加载的每个类使用反射,并从中提取包名。但是,我的应用程序已经遇到了数千个类,所以我需要一种更有效的方法。

我考虑的另一件事是类似于找出类路径中的JAR文件,然后为每个JAR并行执行目录列表。但是,我不知道这是否可以从应用程序/如何做到这一点。

加分

任何建议可以按顶级软件包过滤的方式的人的加分。例如。显示com.xyz ==>下的所有软件包com.xyz.*com.xyz.*.*

谢谢!

3 个答案:

答案 0 :(得分:6)

如果你确实需要安装和扫描jar文件,commons-vfs内置了这个内容。如果你必须走这条路,这可能会让事情变得更容易。

编辑#1:您可以像这样获取类路径(来自示例here):

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 );
                }
            }
        }
    }
}

答案 1 :(得分:3)

http://code.google.com/p/reflections/一个镜头。

  

反射扫描你的类路径,   索引元数据,允许您   在运行时查询它,可以保存和   为许多人收集这些信息   项目中的模块。

答案 2 :(得分:2)

此代码将为您提供所有类路径条目(包括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-)条目,访问所有子目录(recursivly)以及if(并且仅当)目录包含至少一个类文件时,该目录的名称(相对于类路径条目) )可以转换为包名(例如:META_INF是所有jar文件中的目录,但不是包名...)