2

I've been trying to export a JavaFX project as a .jar, but whenever I run it, I get a NullPointerException; supposedly, it can't find the FXML. I'm not sure how to handle this, is there something wrong with my project structure? I looked at: FXML layout not loaded when run jar outside Eclipse, but the solution didn't seem to work with me, and had a different issue.

The project is hosted at: https://github.com/Sunquyman/GameOfLife/tree/master/src

The stack trace I receive when attempting to run:

java.lang.NullPointerException: Location is required.
    at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3207)
    at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3175)
    at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3148)
    at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3124)
    at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3104)
    at javafx.fxml.FXMLLoader.load(FXMLLoader.java:3097)
    at main.Main.start(Main.java:21)
    at com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$162(LauncherImpl.java:863)
    at com.sun.javafx.application.PlatformImpl.lambda$runAndWait$175(PlatformImpl.java:326)
    at com.sun.javafx.application.PlatformImpl.lambda$null$173(PlatformImpl.java:295)
    at java.security.AccessController.doPrivileged(Native Method)
    at com.sun.javafx.application.PlatformImpl.lambda$runLater$174(PlatformImpl.java:294)
    at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
    at com.sun.glass.ui.gtk.GtkApplication._runLoop(Native Method)
    at com.sun.glass.ui.gtk.GtkApplication.lambda$null$49(GtkApplication.java:139)
    at java.lang.Thread.run(Thread.java:745)

Really confused as to why this is happening; if it runs well in Eclipse, why would it break as an export?

Thanks in advance!

Community
  • 1
  • 1
Sunquyman
  • 23
  • 1
  • 4
  • whenever you export it as a .jar, did you include those .fxml files also ? – Damiii May 22 '16 at 22:39
  • Yes, the .jar has the FXML. – Sunquyman May 22 '16 at 22:41
  • One thing for sure is that he is complaining about this line **Parent root = FXMLLoader.load(getClass().getResource("../view/GUI.fxml"));** – Damiii May 22 '16 at 22:44
  • Are you sure that this line is well constructed ? – Damiii May 22 '16 at 22:47
  • try to do something like **FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("sde.fxml")); AnchorPane page = fxmlLoader.load();** – Damiii May 22 '16 at 22:47
  • No, I tried this, yet it didn't seem to work out for me. Also, I think you mean "new FXMLLoader(Main.class.getResource("sde.fxml"))", because you can't run getClass() off of nothing... right? Or am I missing something here – Sunquyman May 22 '16 at 23:09
  • Actually it does work this code. – Damiii May 22 '16 at 23:50
  • Wait, really? Have you produced a working .jar file, if so, can you send it to me? I'm thinking, maybe I'm doing something else wrong, and I could compare yours with mine – Sunquyman May 23 '16 at 00:04
  • 1
    I downloaded your code,it has something to do with (../).If you put the .fxml and .css in the folder main it works but i am wondering why (../) cause this problem... – GOXR3PLUS May 23 '16 at 00:15
  • Ahhh, I think you're on to something here. I eliminated the two periods and just wrote "/view/GUI.fxml" to test, and the .jar found the file! The only thing that broke was the CSS' @fontface url(), which is making me wonder what the relationship is between defining paths and it breaking post-export. Does anyone know? Going to do more testing – Sunquyman May 23 '16 at 00:23
  • I might as well drop by the stack trace from the broken CSS: " May 22, 2016 8:32:58 PM com.sun.javafx.css.StyleManager loadStylesheetUnPrivileged INFO: Could not load @font-face font [jar:file:/home/luiserebii/Desktop/GameOfLife/GameOfLife.jar!/fonts/8bit.ttf] " This is from running the .jar... – Sunquyman May 23 '16 at 00:33
  • your jar is running now?I am asking cause i maked it run :).. – GOXR3PLUS May 23 '16 at 00:37
  • Yes, it is :D, but the CSS is not loading correctly, so the font is broken. This is the only issue that's left... trying to figure out what's wrong with the way I've written it – Sunquyman May 23 '16 at 00:39
  • check the magic answer – GOXR3PLUS May 23 '16 at 00:52

2 Answers2

1

your code:

  Parent root = FXMLLoader.load(getClass().getResource("../view/GUI.fxml"));

try to put GUI.fxml in the resources folder and change the code to this:

  Parent root = FXMLLoader.load(getClass().getResource("GUI.fxml"));
1

First of all you have to create a resources folder like this:

To do this right click on the Project->New->Resource Folder->Name it as you want but a nice option is resources

enter image description here

Then i have modified your code as following here:

Main Class:

public class Main extends Application {
@Override
public void start(Stage primaryStage) {
    try {

        //You have to Load the font before using it into css!!
        Font.loadFont(getClass().getResourceAsStream("/resources/fonts/8bit.ttf"), 14);
        Scene scene = new Scene(new GUIController());
        scene.getStylesheets().add(getClass().getResource("/view/application.css").toExternalForm());
        primaryStage.setScene(scene);
        primaryStage.setTitle("Game of Life Settings");
        primaryStage.show();

    } catch (Exception e) {
        e.printStackTrace();
    }
}

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

GUIController: Keep in mind than in .fxml file i used root and !default Controller so it looks now like this(used SceneBuilder).Basically doing this you can use GUIController class more than one times.

enter image description here

public class GUIController extends AnchorPane implements Initializable {

..........

private final String lotOn = "/music/soundfx/lensoftruth_on.mp3";
private final String lotOff = "/music/soundfx/lensoftruth_off.mp3";

 .......

//Constructor
public GUIController(){
    FXMLLoader loader = new FXMLLoader(getClass().getResource("/view/GUI.fxml"));
    loader.setRoot(this);
    loader.setController(this);

    try {
        loader.load();
    } catch (IOException e) {
        e.printStackTrace();
    }
  }


.......

 }

ABOUT CSS: And finally the in css file i modified this cause the css font is loaded into the code before added with css(check this here):

@font-face {

-fx-font-family: "8bit";

}

And Finally about /:

If you call getResource() for a class and do not prepend a /, the path is considered to be relative to the package of the class.Check this here

Are you happy? :)

Community
  • 1
  • 1
GOXR3PLUS
  • 6,877
  • 9
  • 44
  • 93
  • Yes, thank you! However, I think the part with the resources and loading the css within the code is unnecessary... I tried the CSS font-face line: url('file:fonts/8bit.ttf');, and it ended up working perfectly! So just to reiterate, I think the quick solution for this is to simply use the relative filepath beginning with "/" for FXML and CSS loading, and appending "file:" for relative @font-face loading. Regardless, thank you so much for providing these resources, helped make sense of this more. Especially for providing that key piece of information about the "/", which was very important! – Sunquyman May 23 '16 at 01:11