为什么InputStreamReader在从jar读取时会抛出NPE?

时间:2011-05-16 20:03:44

标签: java jar stream io inputstream

我正在尝试使用流来迭代已知目录中的类文件。最终目标是获取特定包中存在的所有类的类名,然后在运行时加载类并使用反射来获取名称和名称。所有静态常量的值。这在我从我的机器上的源程序运行程序时有效,但是当我以jar形式运行它时,BufferedReader会从ready()readLine()中抛出一个NPE。这是代码(为简洁起见,省略了错误处理和最佳实践):

private void printClassNamesInPackage(final String strPackage) throws Exception {
    // The returned implementation of InputStream seems to be at fault
    final InputStream       packageStream = getClass().getClassLoader().getResourceAsStream( strPackage );
    final InputStreamReader streamReader  = new InputStreamReader( packageStream );
    final BufferedReader    reader        = new BufferedReader( streamReader );
    // Throws NPE from inside ready() - SEE STACKTRACE BELOW
    // reader.ready()
    String strLine;
    // Throws NPE from inside readLine() -  SEE STACKTRACE BELOW
    while ( null != (strLine = reader.readLine()) ) {
        System.out.println( strLine );
    }
}

来自reader.ready() 的堆栈跟踪:

java.lang.NullPointerException
    at java.io.FilterInputStream.available(FilterInputStream.java:142)
    at sun.nio.cs.StreamDecoder.inReady(StreamDecoder.java:343)
    at sun.nio.cs.StreamDecoder.implReady(StreamDecoder.java:351)
    at sun.nio.cs.StreamDecoder.ready(StreamDecoder.java:165)
    at java.io.InputStreamReader.ready(InputStreamReader.java:178)
    at java.io.BufferedReader.ready(BufferedReader.java:436)

来自reader.readLine() 的堆栈跟踪:

java.lang.NullPointerException
    at java.io.FilterInputStream.read(FilterInputStream.java:116)
    at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:264)
    at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:306)
    at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:158)
    at java.io.InputStreamReader.read(InputStreamReader.java:167)
    at java.io.BufferedReader.fill(BufferedReader.java:136)
    at java.io.BufferedReader.readLine(BufferedReader.java:299)
    at java.io.BufferedReader.readLine(BufferedReader.java:362)

逐步执行会显示以下InputStream实现:

  • 来自:java.io.ByteArrayInputStream
  • 来自jar:sun.net.www.protocol.jar.JarURLConnection$JarURLInputStream

进一步了解JarURLInputStream我发现继承的(来自FilterInputStream)字段InputStream innull,这导致了最终的NPE。

不幸的是,这和我在调试器中的深度一样深。

有关如何正确执行此操作的任何想法?我错过了什么或做错了什么?谢谢!

1 个答案:

答案 0 :(得分:2)

文件夹不会返回包含所有文件列表的InputStream。使用JarInputStream以编程方式提取JAR。您可以找到示例here。作为参考,这里有一个略微修改的相关摘录:

public static List<String> getClassNamesInPackage(String jarName, String packageName) throws IOException {
    JarInputStream jarFile = new JarInputStream(new FileInputStream(jarName));
    packageName = packageName.replace(".", "/");
    List<String> classes = new ArrayList<String>();

    try {
        for (JarEntry jarEntry; (jarEntry = jarFile.getNextJarEntry()) != null;) {
            if ((jarEntry.getName().startsWith(packageName)) && (jarEntry.getName().endsWith(".class"))) {
                classes.add(jarEntry.getName().replace("/", "."));
            }
        }
    } finally {
        jarFile.close();
    }

    return classes;
}