I'm trying to iterate over the class files in a known directory using streams. The ultimate goal is to obtain the class names for all classes that exist in a particular package, then load the classes at runtime and use reflection to obtain the names & values of all the static constants. This works when I run the program from source on my machine, but when I run it as a jar the BufferedReader
throws a NPE from both ready()
and readLine()
. Here's the code (with error handling & best practices omitted for brevity):
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 );
}
}
The stacktrace from 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)
The stacktrace from 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)
Stepping through the execution reveals the following InputStream
implementations:
java.io.ByteArrayInputStream
sun.net.www.protocol.jar.JarURLConnection$JarURLInputStream
Looking further into JarURLInputStream
I find that the inherited (from FilterInputStream
) field InputStream in
is null
, which leads to the resulting NPE.
Unfortunately, that's as deep as I was able to get in the debugger.
Any ideas on how to properly do this? What am I missing or doing wrong? Thank you!
Folders don't return an InputStream
with some list of all files or something. Use JarInputStream
to extract the JAR programmatically. You can find an example here. For reference, here's a slight modified extract of relevance:
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;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With