4

Environment: Eclipse, OpenJDK12, Maven, modular project.

My project structure:

src
  \main
  |    \java
  |         \com
  |         |    \myApp
  |         |    |     \otherFolders
  |         |    |     \controllers
  |         |    |                |--ToolBar.java
  |         |    |--MainApp.java
  |         |--module-info.java  
src
  \main
      \resources
            \com
                \myApp
                     |--ToolBar.fxml
                     |--MainApp.fxml
                     \--controllers
                             |--logo.png

Context:

I'm trying to load the image located in /src/main/resources/com/myApp/controllers from outside Eclipse, after use jlink for build and export. It is in the same module, not an external folder, not a different module.

My resources folder structure match the package folder structure. I don't want to put all resources in the root resources folder or in a new package with the java classes. I want to maintain this structure, is this possible?

Error: I'm always getting a: java.lang.NullPointerException: Input stream must not be null when runing the app outside Eclipse.

Research:

I already read most of threads regarding this and I would prefer to not post all the code references as it would be a mess to write the question.

These links are the most near to what I'm asking but couldn't make it work:

Resource from src/main/resources not found after building with maven

How to access resource using class loader in Java 9

Java 9 Module system Resources files location

Making the folder structure leading to your resource match a suitable package in your project.

I already have this

Loading classes and resources in Java 9:

non-class-file resources in a module are encapsulated by default, and hence cannot be located from outside the module unless their effective package is open

My package is open to the class which needs access the resource

Code:

Controller

package com.myApp.controllers;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;

public class ToolBar implements Initializable {

    @FXML
    private ImageView imageViewLogo;

    public ToolBar () {

    }

    @Override


    public void initialize(URL location, ResourceBundle resources) {
            Image img = null;
            try {
             // inside eclipse ok - outside fail
             img = new Image(ToolBar .class.getResourceAsStream("logo.png"));
             System.out.println("Attemp 1:" + img.toString());
            } catch (Exception e) { e.printStackTrace();}
            try {
             // inside eclipse ok - outside fail
             img = new Image(ToolBar .class.getResource("logo.png").toExternalForm());
             System.out.println("Attemp 2:" + img.toString());
            } catch (Exception e) { e.printStackTrace();}
            try {
             // inside eclipse fail - outside fail
             img = new Image(ToolBar.class.getClassLoader().getResource("logo.png").toExternalForm());
             System.out.println("Attemp 3:" + img.toString());
            } catch (Exception e) { e.printStackTrace();}
            try {
             // inside eclipse fail - outside fail
             img = new Image(getClass().getResourceAsStream("/com/myApp/controllers/logo.png"));
             System.out.println("Attemp 4:" + img.toString());
            } catch (Exception e) { e.printStackTrace();}
        imageViewLogo.setImage(img);
  }
}

module-info.java

module myApp {

    requires javafx.controls;
    requires javafx.fxml;
    requires transitive javafx.graphics;
    requires javafx.base;
    requires java.desktop;

    opens com.myApp.controllers to javafx.fxml, javafx.scene.image.Image;

    exports com.myApp;

}

pom

<project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.myApp</groupId>
    <artifactId>myApplicattion</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>12</maven.compiler.source>
        <maven.compiler.target>12</maven.compiler.target>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.openjfx</groupId>
            <artifactId>javafx-graphics</artifactId>
            <version>12.0.1</version>
        </dependency>
        <dependency>
            <groupId>org.openjfx</groupId>
            <artifactId>javafx-controls</artifactId>
            <version>12.0.1</version>
        </dependency>
        <dependency>
            <groupId>org.openjfx</groupId>
            <artifactId>javafx-fxml</artifactId>
            <version>12.0.1</version>
        </dependency>
        <dependency>
            <groupId>org.openjfx</groupId>
            <artifactId>javafx-base</artifactId>
            <version>12.0.1</version>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.0</version>
                <configuration>
                    <release>12</release>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.openjfx</groupId>
                <artifactId>javafx-maven-plugin</artifactId>
                <version>0.0.3</version>
                <configuration>
                    <release>12</release>
                    <stripDebug>true</stripDebug>
                    <compress>2</compress>
                    <noHeaderFiles>true</noHeaderFiles>
                    <noManPages>true</noManPages>
                    <launcher>myApplicattionLauncher</launcher>
                    <jlinkImageName>myApplicattionFX</jlinkImageName>
                    <jlinkZipName>myApplicattionZIP</jlinkZipName>
                    <mainClass>com.myApp.MainApp</mainClass>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

Update

Before trying to do this programatically, I was loading the image from the fxml as follows and it worked fine. Why?

<ImageView...>
    <Image url="@../controllers/logo.png" />
</ImageView>

Update 2

Compiled structure:
com
|  \myApp
|       \controllers
|       |         |--ToolBar.class
|       |         |--logo.png
|       |--MainApp.class
|--module-info.class

I don't know what else to do. Is there any good documentation for this? Any help appreciated.

Naman
  • 27,789
  • 26
  • 218
  • 353
tec
  • 999
  • 3
  • 18
  • 40
  • In a compiled application, there are no `src` folders. That has always been the case. How does your *compiled* structure looks like? – Holger Sep 16 '19 at 14:20
  • I dont know how my compiled structure look like, as jlink encapsulate everything in a self-contained app. I can't see my class files. – tec Sep 16 '19 at 14:25
  • `jlink` doesn’t compile your application. That happens at least two steps before that. First, you compile the source files into class files, then, the class files are put together with the resources (if you did not forget to include them) into a (modular) jar file and only then, `jlink` produces an image out of it. The steps up to the jar file do not differ significantly between modular software and non-modular software. Right at this point, you should be able to inspect the jar file to see whether the contents matches your expectation… – Holger Sep 16 '19 at 14:35
  • The `module-info.java` must be in the default package (`src/main/java`), not in the package `com.myApp`. – howlger Sep 16 '19 at 14:57
  • @howlger as a first step, there has to be a package `com.myApp`. The posted source code of `ToolBar` has no package declaration and I suppose, that’s the root of the problem. However, we don’t see which folders were configured as source folders resp. how the resulting structure in the target folder looks like. – Holger Sep 16 '19 at 15:00
  • @Holger If `myApp` were the source folder, Eclipse would show an error. Having the POM file would be helpful. You are right that the package statement is missing in the code. – howlger Sep 16 '19 at 15:11
  • Updated. Sorry for the delay. I had a mess with '\' and '-' ... Added pom. package declaration was not a problem. I had it. I didn't suppose was neccessary to add it here. Compiled structure looks good. thx for pointing out the jlink thing, @Holger – tec Sep 16 '19 at 15:17
  • If the structure looks like that, `ToolBar.class.getResourceAsStream("logo.png")` should work. It’s precisely meant to locate a resource relative to the .class file. The `ToolBar.class.getResource("logo.png")` alternative is not wrong, but could make problems with JavaFX, as it doesn’t support all protocol types. But this doesn’t apply to `getResourceAsStream` which provides an `InputStream` without the need for JavaFX to understand where it comes from. – Holger Sep 16 '19 at 15:19

0 Answers0