1

I made a Gradle project which uses a classloader to load a text file from the subdirectory resources/text. At this point it works, but when I convert the project into a modular JavaFX program, the same classloader function gives a NullPointerException.

src/main project directory

└───src
    └───main
        ├───java
        │   │   module-info.java
        │   └───app
        │           Main.java
        └───resources
            └───text
                    words.txt

build.gradle

plugins {
    id 'application'
    id 'org.openjfx.javafxplugin' version '0.0.8'
}

sourceCompatibility = 11

repositories {
    jcenter()
}

javafx {
    version = '13.0.1'
    modules = [ 'javafx.controls']
}

mainClassName = 'exMod/app.Main'
jar {
    manifest {
        attributes 'Main-Class': mainClassName
    }
}

module-info.java

module exMod {
    requires javafx.controls;
    exports app;
}

Main.java

package app;

import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

public class Main extends Application {

    public static void main(String[] args){ launch(); }

    public void start(Stage stage){
        stage.setTitle("Hello World!");
        Button button = new Button();
        Label label = new Label();
        button.setText("Click me!");
        button.setOnAction(event -> label.setText(getWords()));

        VBox root = new VBox();
        root.setAlignment(Pos.CENTER);
        root.getChildren().addAll(button, label);
        stage.setScene(new Scene(root, 300, 250));
        stage.show();
    }

    private String getWords(){
        String path = "text/words.txt";
        InputStream inputStream = getClass().getClassLoader().getResourceAsStream(path);
        InputStreamReader isReader = new InputStreamReader(inputStream); // null exception
        BufferedReader reader = new BufferedReader(isReader);
        StringBuilder content = new StringBuilder();
        try {
            String line;
            while( (line = reader.readLine()) != null) {
                content.append(line);
            }
        } catch(IOException e){
                e.printStackTrace();
        }
        return content.toString();
    }
}

If I change the path variable to "words.txt" and move the text file up one level to src/main/resources, it works, but for a reason I haven't been able to discover, loading the file from a resource subdirectory will not work. What is causing the NullPointerException and how can I fix it?

Jack J
  • 1,514
  • 3
  • 20
  • 28
  • I didn't think it was important enough to include in my question, so I'll state it here: My words.txt file consists of only this sentence "The red fox jumped over the lazy dog." – Jack J Mar 26 '20 at 01:49

1 Answers1

1

In a comment to this question, as an alternative to program.class.getClassLoader().getResource("b/text.txt") the user Holger states

... you should use program.class.getResource("b/text.txt"), to resolve a resource relative to the location of the program class. Otherwise, it may fail in Java 9 or newer, once you use modules, as going up to the class loader will destroy the information about the actual module.

Because of this I tried to use just getClass().getResourceAsStream(path) instead of getClass().getClassLoader().getResourceAsStream(path).

I also read Alan Bateman's comment on this question where he states

The resource is encapsulated so it can't be found with the ClassLoader APIs. I assume ComboBoxStyling.class..getResource("/css/styleclass.css") will work - note the leading slash so that it is found relative to the root location of the module, not relative to ComboBoxStyling.class in this case.

So I happened to try this combination together, and it worked!

getWords()

private String getWords(){
        String path = "/text/words.txt";
        InputStream in = getClass().getResourceAsStream(path);
        BufferedReader reader = new BufferedReader(new InputStreamReader(in));
        StringBuilder content = new StringBuilder();
        try {
            String line;
            while( (line = reader.readLine()) != null) {
                content.append(line);
            }
        } catch(IOException e){
                e.printStackTrace();
        }
        return content.toString();
    }
Jack J
  • 1,514
  • 3
  • 20
  • 28