4

I am trying to load a FXML file from resources directory to show a JavaFX window, however whatever I do I am unable to find the correct way to reference the resource.

My directory structure is as follows:

src
    main
        java
            gui
                App.java
            module-info.java
        resources
            MainWindow.fxml
out
    production
        classes
            // All compiled classes
        resources
            MainWindow.fxml

The contents of module-info.java are following:

module MyApp {
    requires javafx.controls;
    requires javafx.graphics;
    requires javafx.fxml;
    exports gui;
}

I'm trying to load the MainWindow.fxml file in App.java like this: getClass().getResource("/MainWindow.fxml");

I've tried using MainWindow.fxml and /MainWindow.fxml names, however both return null. As can be seen from the directory structure, contents of resources are copied as well, so they should be available at runtime. Resources directory is marked as such in IntelliJ. I'm using Gradle for dependency management.

How can I load files from the resources directory?

Here's my build.gradle file:

plugins {
    id 'application'
    id 'java'
    id 'org.openjfx.javafxplugin' version '0.0.5'
}

group 'MyApp'
version '1.0-SNAPSHOT'

sourceCompatibility = 1.11

javafx {
    modules = [
            'javafx.controls',
            'javafx.graphics',
            'javafx.fxml'
    ]
}

repositories {
    mavenCentral()
}

dependencies {
    testImplementation group: 'junit', name: 'junit', version: '4.12'

    implementation 'org.openjfx.javafx-controls:11.0.1'
    implementation 'org.openjfx.javafx-fxml:11.0.1'
    implementation 'org.openjfx.javafx-graphics:11.0.1'
}
elect
  • 6,765
  • 10
  • 53
  • 119
user_4685247
  • 2,878
  • 2
  • 17
  • 43
  • Maybe: `App.class.getResource("../resources/MainWindow.fxml");`? – Flown Jan 02 '19 at 19:40
  • I've tried "../resources/MainWindow.fxml", "/resources/MainWindow.fxml", "resources/MainWindow.fxml", neither of them return a resource. – user_4685247 Jan 02 '19 at 19:45
  • For starters, you should open your project to the fxml module, like `opens gui to javafx.fxml`, as in this [sample](https://github.com/openjfx/samples/blob/master/IDE/IntelliJ/Modular/Gradle/hellofx/src/main/java/module-info.java#L5). Are you using the JavaFX [gradle plugin](https://github.com/openjfx/javafx-gradle-plugin)? Can you show your build.gradle file? – José Pereda Jan 02 '19 at 20:19
  • @JoséPereda I've added the build.gradle file. I've also added the opens statement, but I think this may be some other issue, since the file cannot be loaded before any related JavaFX is executed. – user_4685247 Jan 02 '19 at 20:25
  • You don't need the `implementation` part, the plugin does that for you. Also you don't need to add `javafx.graphics`, it is added by controls. As for your issue, do you have an exception? Can you post the stacktrace? Have you tried to run the sample I linked before, does it work for you? – José Pereda Jan 02 '19 at 20:28
  • Yes, the sample works (the one where the controls are added programatically). I get the "Location is not set." exception, but I've pinpointed that to getResource() returning null – user_4685247 Jan 02 '19 at 20:31
  • @tofiffe can you please try to build jar (`$ ./gradlew jar` also it might be necessary to specify the main class: `jar { manifest { attributes 'Main-Class': 'gui.App' } }`) and access the resource using: `InputStream asStream = App.class.getModule().getResourceAsStream("MainWindow.fxml");` – Denis Zavedeev Jan 02 '19 at 20:44
  • If you have an stacktrace in your project(due to the location is not set), add it to the question. Do you say the linked samples with FXML don't work for you? – José Pereda Jan 02 '19 at 20:51
  • @caco3 by building the jar I get `Error: Could not find or load main class gui.App Caused by: java.lang.NoClassDefFoundError: javafx/application/Application` – user_4685247 Jan 02 '19 at 20:53
  • You shouldn't need to build the jar just to make this work... The jar won't have the JavaFX classes in the first place... – José Pereda Jan 02 '19 at 20:55
  • @JoséPereda Oh, yes you're right. Running the main method which tries to access the resource from IntelliJ produces the `NullPointerException` but built jar does not – Denis Zavedeev Jan 02 '19 at 21:02
  • Oh... Seems I managed to run it in Idea: adding `apply plugin: 'idea' idea { module { inheritOutputDirs = true } }` to `build.gradle` worked for me... (See [this](https://stackoverflow.com/questions/48673769/java-9-module-system-resources-files-location) question) – Denis Zavedeev Jan 02 '19 at 21:03
  • @caco3 adding the idea plugin and inheritOutputDirs worked! Can you post this as answer so I can accept it? – user_4685247 Jan 03 '19 at 07:07
  • The issue here seems to be that the the resources aren't in out/production/classes, hence they are not in the module. If the classes and resources are packaged in a JAR file then App.class.getResource("/MainWindow.fxml") should work - the leading slash is to locate it via an absolute resource name. The only way to fix the exploded case is to patch the module to add the contents of out/production/resources to the module, i.e. `--patch-module MyApp=out/production/resources`. – Alan Bateman Jan 03 '19 at 07:45
  • @AlanBateman I’d say, if the classes and resources are packaged in a jar file in this specific way, the application would not even start, as it is not possible to specify a sub-directory within a jar file as class path element. – Holger Jan 10 '19 at 15:37

0 Answers0