-
Bug
-
Resolution: Fixed
-
P4
-
8u65, 9
-
b126
-
generic
-
generic
-
Verified
FULL PRODUCT VERSION :
openjdk version "1.8.0_65"
OpenJDK Runtime Environment (build 1.8.0_65-b17)
OpenJDK 64-Bit Server VM (build 25.65-b01, mixed mode)
ADDITIONAL OS VERSION INFORMATION :
Fedora 22, Linux 4.1.8-200.fc22.x86_64 #1 SMP
A DESCRIPTION OF THE PROBLEM :
Class.getResourceAsStream("directory") (note the absence of a trailing slash) for an existing directory named "directory" in a JAR file returns an internally broken InputStream that throws a NullPointerException on subsequent operations.
This appears to be related toJDK-8039169.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1. In a class, contained in a JAR archive containing a directory (named "directory" for illustrative purposes), aquire an InputStream for the directory using Class.getResourceAsStream("directory") (note the absence of a trailing slash).
2. Observe that the InputStream returned is not null.
3. Perform an operation on the InputStream, for example InputStream.available().
4. Observe a NullPointerException being thrown.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
In (2.), the expected return value of Class.getResourceAsStream("directory") would be either be null, or an empty InputStream (i.e. with InputStream.available() == 0).
ACTUAL -
In (2.), a non-null InputStream is returned. However, subsequent operations using the InputStream cause a NullPointerException to be thrown.
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
=== Main.java ===
import java.io.InputStream;
class Main {
public static void main(String[] args) {
String[] files = new String[] {
"non-existant-file", // A file that does not exist in the JAR
"directory", // An existing directory, without trailing slash
"directory/" // An existing directory, with trailing slash
};
for (String file : files) {
InputStream is = Main.class.getResourceAsStream(file);
String threw = "n/a";
if (is != null) {
try {
is.available();
threw = "";
} catch (Throwable e) {
threw = e.getClass().getName();
}
}
System.out.println(file + ": InputStream=" + is + ", threw=" + threw);
}
}
}
=== Usage ===
mkdir directory
javac Main.java
jar cfe example.jar Main Main.class directory/
java -jar example.jar
=== Observed output ===
non-existant-file: InputStream=null, threw=n/a
directory: InputStream=sun.net.www.protocol.jar.JarURLConnection$JarURLInputStream@5c647e05, threw=java.lang.NullPointerException
directory/: InputStream=sun.net.www.protocol.jar.JarURLConnection$JarURLInputStream@55f96302, threw=-
=== Expected output ===
non-existant-file: InputStream=null, threw=n/a
directory: InputStream=sun.net.www.protocol.jar.JarURLConnection$JarURLInputStream@5c647e05, threw=-
directory/: InputStream=sun.net.www.protocol.jar.JarURLConnection$JarURLInputStream@55f96302, threw=-
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
Check the validity of the returned InputStream by a construct like:
InputStream is = getClass().getResourceAsStream(file);
try {
is.available();
} catch(NullPointerException e) {
// Handle invalid InputStream
}
openjdk version "1.8.0_65"
OpenJDK Runtime Environment (build 1.8.0_65-b17)
OpenJDK 64-Bit Server VM (build 25.65-b01, mixed mode)
ADDITIONAL OS VERSION INFORMATION :
Fedora 22, Linux 4.1.8-200.fc22.x86_64 #1 SMP
A DESCRIPTION OF THE PROBLEM :
Class.getResourceAsStream("directory") (note the absence of a trailing slash) for an existing directory named "directory" in a JAR file returns an internally broken InputStream that throws a NullPointerException on subsequent operations.
This appears to be related to
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1. In a class, contained in a JAR archive containing a directory (named "directory" for illustrative purposes), aquire an InputStream for the directory using Class.getResourceAsStream("directory") (note the absence of a trailing slash).
2. Observe that the InputStream returned is not null.
3. Perform an operation on the InputStream, for example InputStream.available().
4. Observe a NullPointerException being thrown.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
In (2.), the expected return value of Class.getResourceAsStream("directory") would be either be null, or an empty InputStream (i.e. with InputStream.available() == 0).
ACTUAL -
In (2.), a non-null InputStream is returned. However, subsequent operations using the InputStream cause a NullPointerException to be thrown.
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
=== Main.java ===
import java.io.InputStream;
class Main {
public static void main(String[] args) {
String[] files = new String[] {
"non-existant-file", // A file that does not exist in the JAR
"directory", // An existing directory, without trailing slash
"directory/" // An existing directory, with trailing slash
};
for (String file : files) {
InputStream is = Main.class.getResourceAsStream(file);
String threw = "n/a";
if (is != null) {
try {
is.available();
threw = "";
} catch (Throwable e) {
threw = e.getClass().getName();
}
}
System.out.println(file + ": InputStream=" + is + ", threw=" + threw);
}
}
}
=== Usage ===
mkdir directory
javac Main.java
jar cfe example.jar Main Main.class directory/
java -jar example.jar
=== Observed output ===
non-existant-file: InputStream=null, threw=n/a
directory: InputStream=sun.net.www.protocol.jar.JarURLConnection$JarURLInputStream@5c647e05, threw=java.lang.NullPointerException
directory/: InputStream=sun.net.www.protocol.jar.JarURLConnection$JarURLInputStream@55f96302, threw=-
=== Expected output ===
non-existant-file: InputStream=null, threw=n/a
directory: InputStream=sun.net.www.protocol.jar.JarURLConnection$JarURLInputStream@5c647e05, threw=-
directory/: InputStream=sun.net.www.protocol.jar.JarURLConnection$JarURLInputStream@55f96302, threw=-
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
Check the validity of the returned InputStream by a construct like:
InputStream is = getClass().getResourceAsStream(file);
try {
is.available();
} catch(NullPointerException e) {
// Handle invalid InputStream
}