Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8144977

Class.getResourceAsStream("directory") in JAR returns broken InputStream

XMLWordPrintable

    • 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 to JDK-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
      }

            sherman Xueming Shen
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            7 Start watching this issue

              Created:
              Updated:
              Resolved: