Why does the getResource() method return null in JDK 11?

Alexey :

Simple Java program:

public static String loadText(String file) {
    StringBuilder finalString = new StringBuilder();

    InputStream in = null;
    BufferedReader reader = null;
    InputStreamReader isr = null;

    try{
        System.out.println("Text File: " + file);

        // Version 1
        //URL url = Thread.currentThread().getClass().getResource(file); 
        //in = url.openStream();

        // Version 2
        in = Class.class.getResourceAsStream(file);

        isr = new InputStreamReader(in);
        reader = new BufferedReader(isr);
        String line;
        while((line = reader.readLine()) != null) {
            finalString.append(line).append("//\n");
        }
    }
    catch(IOException e) {
        e.printStackTrace();
        System.exit(-1);
    }
    finally {
        try {
            if (isr != null) { isr.close(); }
            if (reader != null) { reader.close(); }
            if (in != null) { in.close(); }
            } catch (IOException e) { e.printStackTrace(); }
        }
    return finalString.toString();
}

The getResource and getResourceAsStream methods works fine in JDK 8 (java-8-openjdk-amd64) but they always return null in JDK 11.

Questions: Why? And how can I fix this?

  • Operation System: Linux Mint 19 Tara x64
  • IDE: Eclipse 2018-12 (4.10.0)
Svetlin Zarev :

I've tried your application with both openjdk 8 and 11 on MacOS and it does not work with both. I think you need to look at [1] and [2] in order to understand how getResourceAsStream works.

TLDR:

  1. If the path is absolute (i.e. starts with a slash - /), then class.getResourceAsStream() searches in the provided path

  2. If the path is NOT absolute (i.e. does not start with a slash) , then class.getResourceAsStream() searches in a constructed path that corresponds to the package name, where the dots are replaced with slashes

So whether it works or not depends on 2 things:

  1. Is your path absolute or not ?
  2. Is the file located in the same package as the class or not ?

Basically in your exaple as is provided, it can never work if the path is not absolute, because Class.class.getResourceAsStream() will always resolve the path to java/lang/<file>, so your file must be in a system package. So instead you must use <MyClass>.class.getResourceAsStream() or alternatively use an absolute path

[1] https://docs.oracle.com/javase/7/docs/api/java/lang/ClassLoader.html#getResource(java.lang.String)

[2] https://docs.oracle.com/javase/7/docs/api/java/lang/Class.html#getResource%28java.lang.String%29


Update

Since Java SE 9, invoking getResourceXXX on a class in a named module will only locate the resource in that module, it will not search the class path as it did in previous release. So when you use Class.class.getResourceAsStream() it will attempt to locate the resource in module containing java.lang.Class, which is the java.base module. Obviously your resource is not in that module, so it returns null.

You have to make java 9+ search for the file in your module, which most probably is an "unnamed module". You can do that by changing Class to any class defined in your module in order to make java use the proper class loader.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=73245&siteId=1