Java 为什么InputStreamReader在从jar读取时抛出NPE?
我试图使用streams在已知目录中迭代类文件。最终目标是获取特定包中存在的所有类的类名,然后在运行时加载这些类,并使用反射来获取所有静态常量的名称和值。当我在我的机器上从源代码运行程序时,这是可行的,但当我将其作为jar运行时,Java 为什么InputStreamReader在从jar读取时抛出NPE?,java,jar,stream,io,inputstream,Java,Jar,Stream,Io,Inputstream,我试图使用streams在已知目录中迭代类文件。最终目标是获取特定包中存在的所有类的类名,然后在运行时加载这些类,并使用反射来获取所有静态常量的名称和值。当我在我的机器上从源代码运行程序时,这是可行的,但当我将其作为jar运行时,BufferedReader会从ready()和readLine()抛出一个NPE。以下是代码(为了简洁起见,省略了错误处理和最佳实践): 来自reader.ready()的堆栈跟踪: 来自reader.readLine()的堆栈跟踪: 单步执行将显示以下InputSt
BufferedReader
会从ready()
和readLine()
抛出一个NPE。以下是代码(为了简洁起见,省略了错误处理和最佳实践):
来自reader.ready()的堆栈跟踪:
来自reader.readLine()的堆栈跟踪:
单步执行将显示以下InputStream
实现:
- 源代码:
java.io.ByteArrayInputStream
- 来自jar:
sun.net.www.protocol.jar.JarURLConnection$JarURLInputStream
进一步查看JarURLInputStream
我发现
中继承的(来自FilterInputStream
)字段InputStream为null
,这导致产生NPE
不幸的是,这是我在调试器中所能达到的深度
关于如何正确地做到这一点有什么想法吗?我错过了什么或做错了什么?谢谢大家! 文件夹不会返回包含所有文件列表或其他内容的InputStream
。用于以编程方式提取JAR。你可以找到一个例子。作为参考,这里有一个稍微修改的相关性摘录:
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;
}
publicstaticlist getClassNamesInPackage(stringjarname,stringpackagename)抛出IOException{
JarInputStream jarFile=newjarinputstream(newfileinputstream(jarName));
packageName=packageName.replace(“.”,“/”);
列表类=新的ArrayList();
试一试{
for(JarEntry-JarEntry;(JarEntry=jarFile.getNextJarEntry())!=null;){
if((jarEntry.getName().startsWith(packageName))&&(jarEntry.getName().endsWith(“.class”)){
add(jarEntry.getName().replace(“/”,“);
}
}
}最后{
jarFile.close();
}
返回类;
}
总而言之,您试图获取文件夹的InputStream
,而不是文件,对吗?是否可能是“getClass().getClassLoader().getResourceAsStream(strPackage)”;“返回空值?”@BalusC:是的。最初的实现只是为strPackage
目录创建了一个新文件
,然后使用listFiles()
获取其中的类。我正在对其进行重构,以使用流而不是文件对象,这样我们就可以支持从jar执行。@JustinKSU:不,正如您所看到的,我提供了由getResourceAsStream
返回的运行时实现。文件夹不会返回包含所有文件列表或其他内容的InputStream
。使用JarInputStream
以编程方式提取JAR。感谢您的回复,我不知道JarInputStream
类。这可能很好,但我关心的是jar名称的需要——为什么没有解决方案可以保证我从jar加载而不是从本地文件系统加载的事实是透明的?我还没试过,但我会告诉你我发现了什么。它确实存在,但不是你想要的方式。只有通过名称知道类路径上的项,才能引用它们。然后类加载器透明地处理加载:它可能从文件、JAR、网络套接字等加载。没有通用方法列出这些项。
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)
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)
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;
}