4

I have been looking around for the proper way to include FXML and images in the build.gradle so that they are build into the jar. I have look here and tried it but it still does not work.

Throws this error: java.lang.NullPointerException: inputStream is null.

Here is the build.gradle (Github):

group 'com.voidustries'
version '1.0-SNAPSHOT'

sourceSets {
    main {
        resources {
            srcDirs = ["src/main/java/com/voidustries/poly"]
            includes = ["gui/layoutForm.fxml"]
        }
    }
}

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath 'org.junit.platform:junit-platform-gradle-plugin:1.1.0'
    }
}

apply plugin: 'java'
apply plugin: 'org.junit.platform.gradle.plugin'

repositories {
    mavenCentral()
}

dependencies {
    testCompile('org.junit.jupiter:junit-jupiter-api:5.1.0')
    testRuntime('org.junit.jupiter:junit-jupiter-engine:5.1.0')
}

task wrapper(type: Wrapper) {
    description = 'Generates gradlew[.bat] scripts'
    gradleVersion = '4.3.1'
}

test {
    testLogging {
        events "passed", "skipped", "failed"
    }
}

Here is GUI.java (Github):

FXMLLoader loader = new FXMLLoader();
FileInputStream fis = new FileInputStream(settings);
ResourceBundle resourceBundle = new PropertyResourceBundle(fis);
loader.setResources(resourceBundle);

Parent root = loader.load(getClass().getResourceAsStream("layoutForm.fxml"));
Platform.setImplicitExit(false);

The stacktrace says that loader.load(getClass().getResourceAsStream("layoutForm.fxml")); is causing the error

Here is the source Tree:

com
└───voidustries
    └───poly
        │   CustomFormatter.java
        │   Main.java
        │   PolyThreads.java
        │   SysTray.java
        │
        ├───gui
        │       Controller.java
        │       GUI.java
        │       Icon.png
        │       layoutForm.fxml
        │
        └───img
                Icon.png

you can see that layoutForm.fxml and Icon.png are both there in the tree

Here is the Out tree:

com
└───voidustries
    └───poly
        │   CustomFormatter.class
        │   Main.class
        │   PolyThreads.class
        │   SysTray.class
        │
        └───gui
                Controller.class
                GUI.class

In the out tree they are both absent and I have been fiddling for hours trying to fix this issue. Any help would be greatly appreciated.

Also if you need more here is the Github repository

Stone Monarch
  • 325
  • 2
  • 15
  • 1
    Have you tried putting the FXML and image file under the `resources` file instead of having them under sources? i.e. follow the standard Maven project layout file structure. – D-Dᴙum Feb 23 '18 at 08:03
  • Maven standard directlry layout: https://maven.apache.org/guides/introduction/introduction-to-the-standard-directory-layout.html – D-Dᴙum Feb 23 '18 at 08:13
  • @Kerry the OP is clearly using gradle, why send them to maven docs? – lance-java Feb 23 '18 at 09:37
  • @lance-java because I think gradle uses the Maven file structure by default? – D-Dᴙum Feb 23 '18 at 15:10
  • @Kerry there are some similarities... but makes much more sense to link to [gradle java plugin docs](https://docs.gradle.org/current/userguide/java_plugin.html#sec:java_project_layout) – lance-java Feb 23 '18 at 21:50
  • @lance-java does it really matter when my comment refers to the Maven file structure? – D-Dᴙum Feb 23 '18 at 22:45
  • 1
    Yes, because `src/main/filters`, `src/assembly` and `src/site` etc mentioned in the Maven docs are not applicable to Gradle and could cause confusion. – lance-java Feb 23 '18 at 22:49

2 Answers2

7

Just to add my thre'penny bit for anyone not getting satisfaction:

Under src/main/resources (Windows src\main\resources) you seem to have to make the "location" of your resource file match the classpath used to run your .class files.

I have concluded this (until a more knowledgeable person says otherwise) from playing around with an .fxml file in a JavaFX gradle project.

The class Main (containing main()) is in a package called "sample"... so the path to the .java file is ...\EclipseWorkspace\TestFXexp\src\main\java\sample\Main.java.

This appears to mean that your .fxml file has to go here: ...\EclipseWorkspace\TestFXexp\src\main\resources\ sample\config.fxml.

gradle installdist will then correctly package up the .jar for deployment. Expanding the .jar you find that config.xml has been put under directory sample\ along with the .class files... and that the Main.class file is able to find it and use it.

When I put the config.fxml like this: ...\EclipseWorkspace\TestFXexp\src\main\resources\config.fxml ... it didn't work: the config.fxml is put then outside the sample package in the .jar file and the Main.class file can't find it.

mike rodent
  • 14,126
  • 11
  • 103
  • 157
  • I'd say you're correct with that conclusion. But I don't like the fact that Gradle wants us to change how we've done this previously. For images and other true "resources" it makes sense, but FXML files are essentially just shorthand .java files which do instantiation, add children to containers, and set properties. We frequently work on both FXML files and their controllers, and I would not appreciate having to open two totally separate "mirror" directory structures just to get to the FXML I need. Not to mention the hassle of move refactors requiring us to move files in two folders. – Manius Apr 28 '19 at 16:43
  • Plus, I'm much less likely to switch from a NetBeans Ant JavaFX project to a Gradle project if I know I have to manually move dozens or hundreds of FXML files to this separate directory structure. IMO this is a case where it makes sense to override Gradle's regular convention, just for FXML files. – Manius Apr 28 '19 at 16:44
2

You are putting xml files in a folder called src/main/java (hint: java dir is for java files)

Resources (eg xml, image files etc) should go in src/main/resources

This is a standard convention followed by both Maven and Gradle. If you want to change the defaults you can, but first I strongly advise you consider following the sensible conventions.

Also, a note on classloaders

  • SomeClass.class.getResource("foo.xml") will look for the xml relative to the class package
  • SomeClass.class.getResource("/foo.xml") will look for the xml relative to the classpath root

So in your example

getClass().getResourceAsStream("layoutForm.fxml")

This is looking for a file on the classpath com/voidustries/poly/gui/layoutForm.fxml

So if you want to leave your resources where they are, you will want to add src/main/java to the resource folders, not src/main/java/com/voidustries/poly

lance-java
  • 25,497
  • 4
  • 59
  • 101