FXMLLoader raises “Location is not set”, even though file exists on location Code Answer

I have a JavaFX project that I compile/run with Maven. This is how I load my login screen:

String path = "/org/openjfx/fxml/login.fxml";
URL url = getClass().getResource(path);
Parent root = FXMLLoader.load(url);

It runs neatly. url is evaluated to file:/home/allan/IdeaProjects/california-maven/target/classes/org/openjfx/fxml/login.fxml.

However, when I try to render another FXML file with this same code, I get javafx.fxml.LoadException caused by java.lang.IllegalStateException: Location is not set.. The file’s full url (passed to FXMLLoader) is file:/home/allan/IdeaProjects/california-maven/target/classes/org/openjfx/fxml/sign-up.fxml.

Which is odd, since both files exist on that location:

a print of the folder structure, depicting that both files exist on that location

I wonder if this is a problem with sign-up.fxml. Code below:

<?xml version="1.0" encoding="UTF-8"?>

<?import org.openjfx.components.*?>
<?import javafx.geometry.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.text.*?>

<ScrollPane hbarPolicy="NEVER" maxHeight="-Infinity" minHeight="-Infinity" minViewportHeight="768.0" minWidth="-Infinity" prefHeight="768.0" prefViewportWidth="768.0" prefWidth="1024.0" styleClass=".root-scroll-pane" stylesheets="@../css/index.css" xmlns="http://javafx.com/javafx/10.0.2-internal" xmlns:fx="http://javafx.com/fxml/1" fx:controller="org.openjfx.controllers.SignUpController">
   <content>
      <VBox prefHeight="1068.0" prefWidth="1024.0" styleClass="root-vbox" stylesheets="@../css/sign-up.css">
         <children>
            <HBox spacing="25.0">
               <VBox.margin>
                  <Insets bottom="55.0" />
               </VBox.margin>
               <children>
                  <GoBackButton />
                  <Label text="Criar conta">
                     <font>
                        <Font name="System Bold" size="50.0" />
                     </font>
                  </Label>
               </children>
               <padding>
                  <Insets left="-20.0" />
               </padding>
            </HBox>
            <FormField fx:id="nameField" fieldLabelText="Nome:" promptText="Ex: Allan">
               <VBox.margin>
                  <Insets bottom="40.0" />
               </VBox.margin>
            </FormField>
            <FormField fx:id="usernameField" fieldLabelText="Nome de usuário:" promptText="Ex: allan">
               <VBox.margin>
                  <Insets bottom="40.0" />
               </VBox.margin>
            </FormField>
            <FormField fx:id="emailField" fieldLabelText="Email:" promptText="Ex: allan@agill.com">
               <VBox.margin>
                  <Insets bottom="40.0" />
               </VBox.margin>
            </FormField>
            <FormField fx:id="passwordField" fieldLabelText="Senha:" isPasswordField="true">
               <VBox.margin>
                  <Insets bottom="40.0" />
               </VBox.margin>
            </FormField>
            <FormField fx:id="confirmPasswordField" fieldLabelText="Confirme sua senha:" isPasswordField="true">
               <VBox.margin>
                  <Insets bottom="40.0" />
               </VBox.margin>
            </FormField>
            <Button fx:id="signUpButton" mnemonicParsing="false" onAction="#signUpButtonClicked" prefHeight="60.0" prefWidth="800.0" styleClass="sign-up-button" stylesheets="@../css/sign-up.css" text="CRIAR">
               <font>
                  <Font name="System Bold" size="20.0" />
               </font>
            </Button>
         </children>
         <padding>
            <Insets left="85.0" top="60.0" />
         </padding>
      </VBox>
   </content>
</ScrollPane>

EDIT 1:

The login screen is loaded in Main.java. The sign up screen is loaded by a file called NavigationService.java, that lives inside org.openjfx.services. This is the loading code on NavigationService:

 private Scene buildScene(String routeName) {
        String path = "/org/openjfx/fxml/" + routeName + ".fxml";
        URL url = getClass().getResource(path);
        System.out.println("Trying to load: " + url);

        try {
            Parent root = FXMLLoader.load(url);

            Dimensions dimensions = Dimensions.getPrefferedSize(routeName);

            return new Scene(root, dimensions.getWidth(), dimensions.getHeight());
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

Full stack trace:

javafx.fxml.LoadException: 
/home/allan/IdeaProjects/california-maven/target/classes/org/openjfx/fxml/sign-up.fxml:18

    at javafx.fxml/javafx.fxml.FXMLLoader.constructLoadException(FXMLLoader.java:2625)
    at javafx.fxml/javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2603)
    at javafx.fxml/javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2466)
    at javafx.fxml/javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3237)
    at javafx.fxml/javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3194)
    at javafx.fxml/javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3163)
    at javafx.fxml/javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3136)
    at javafx.fxml/javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3113)
    at javafx.fxml/javafx.fxml.FXMLLoader.load(FXMLLoader.java:3106)
    at org.openjfx/org.openjfx.services.NavigationService.buildScene(NavigationService.java:43)
    at org.openjfx/org.openjfx.services.NavigationService.push(NavigationService.java:55)
    at org.openjfx/org.openjfx.controllers.LoginController.signUpLinkClicked(LoginController.java:74)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:566)
    at com.sun.javafx.reflect.Trampoline.invoke(MethodUtil.java:76)
    at jdk.internal.reflect.GeneratedMethodAccessor2.invoke(Unknown Source)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:566)
    at javafx.base/com.sun.javafx.reflect.MethodUtil.invoke(MethodUtil.java:273)
    at javafx.fxml/com.sun.javafx.fxml.MethodHelper.invoke(MethodHelper.java:83)
    at javafx.fxml/javafx.fxml.FXMLLoader$MethodHandler.invoke(FXMLLoader.java:1784)
    at javafx.fxml/javafx.fxml.FXMLLoader$ControllerMethodEventHandler.handle(FXMLLoader.java:1670)
    at javafx.base/com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:86)
    at javafx.base/com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
    at javafx.base/com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
    at javafx.base/com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
    at javafx.base/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
    at javafx.base/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at javafx.base/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
    at javafx.base/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at javafx.base/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
    at javafx.base/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at javafx.base/com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
    at javafx.base/com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:49)
    at javafx.base/javafx.event.Event.fireEvent(Event.java:198)
    at javafx.graphics/javafx.scene.Node.fireEvent(Node.java:8890)
    at javafx.controls/javafx.scene.control.Hyperlink.fire(Hyperlink.java:156)
    at javafx.controls/com.sun.javafx.scene.control.behavior.ButtonBehavior.mouseReleased(ButtonBehavior.java:206)
    at javafx.controls/com.sun.javafx.scene.control.inputmap.InputMap.handle(InputMap.java:274)
    at javafx.base/com.sun.javafx.event.CompositeEventHandler$NormalEventHandlerRecord.handleBubblingEvent(CompositeEventHandler.java:218)
    at javafx.base/com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:80)
    at javafx.base/com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
    at javafx.base/com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
    at javafx.base/com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
    at javafx.base/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
    at javafx.base/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at javafx.base/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
    at javafx.base/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at javafx.base/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
    at javafx.base/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at javafx.base/com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
    at javafx.base/com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:54)
    at javafx.base/javafx.event.Event.fireEvent(Event.java:198)
    at javafx.graphics/javafx.scene.Scene$MouseHandler.process(Scene.java:3862)
    at javafx.graphics/javafx.scene.Scene.processMouseEvent(Scene.java:1849)
    at javafx.graphics/javafx.scene.Scene$ScenePeerListener.mouseEvent(Scene.java:2590)
    at javafx.graphics/com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:409)
    at javafx.graphics/com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:299)
    at java.base/java.security.AccessController.doPrivileged(Native Method)
    at javafx.graphics/com.sun.javafx.tk.quantum.GlassViewEventHandler.lambda$handleMouseEvent$2(GlassViewEventHandler.java:447)
    at javafx.graphics/com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(QuantumToolkit.java:412)
    at javafx.graphics/com.sun.javafx.tk.quantum.GlassViewEventHandler.handleMouseEvent(GlassViewEventHandler.java:446)
    at javafx.graphics/com.sun.glass.ui.View.handleMouseEvent(View.java:556)
    at javafx.graphics/com.sun.glass.ui.View.notifyMouse(View.java:942)
    at javafx.graphics/com.sun.glass.ui.gtk.GtkApplication._runLoop(Native Method)
    at javafx.graphics/com.sun.glass.ui.gtk.GtkApplication.lambda$runLoop$11(GtkApplication.java:277)
    at java.base/java.lang.Thread.run(Thread.java:834)
Caused by: java.lang.IllegalStateException: Location is not set.
    at javafx.fxml/javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2459)
    at javafx.fxml/javafx.fxml.FXMLLoader.load(FXMLLoader.java:2435)
    at org.openjfx/org.openjfx.components.GoBackButton.<init>(GoBackButton.java:18)
    at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:490)
    at java.base/java.lang.Class.newInstance(Class.java:584)
    at javafx.fxml/javafx.fxml.FXMLLoader$InstanceDeclarationElement.constructValue(FXMLLoader.java:1019)
    at javafx.fxml/javafx.fxml.FXMLLoader$ValueElement.processStartElement(FXMLLoader.java:754)
    at javafx.fxml/javafx.fxml.FXMLLoader.processStartElement(FXMLLoader.java:2722)
    at javafx.fxml/javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2552)
    ... 67 more

EDIT 2:

GoBackButton.java

package org.openjfx.components;

import javafx.fxml.FXML;
import org.openjfx.services.NavigationService;
import javafx.fxml.FXMLLoader;
import javafx.scene.control.Button;

import java.io.IOException;
import java.net.URL;

public class GoBackButton extends Button {
    public GoBackButton() {
        URL url = getClass().getResource("/org/openjfx/fxml/go-back-button.fxml");
        FXMLLoader loader = new FXMLLoader(url);

        try {
            loader.load();
        } catch (IOException exception) {
            throw new RuntimeException(exception);
        }
    }

    public void onAction() {
        NavigationService.getInstance().pop();
    }
}

go-back-button.fxml

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.Button?>
<?import javafx.scene.image.Image?>
<?import javafx.scene.image.ImageView?>

<fx:root mnemonicParsing="false" fx:controller="org.openjfx.components.GoBackButton" onAction="#onAction" prefHeight="65.0" prefWidth="98.0" style="-fx-background-color: transparent;" styleClass="go-back-button" type="Button" xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1">
    <graphic>
        <ImageView fitHeight="64.0" fitWidth="48.0" pickOnBounds="true" preserveRatio="true">
            <Image url="@../img/arrow-left.png" />
        </ImageView>
    </graphic>
</fx:root>

The error still happens when I try to render the sign up page, but now the StackTrace changed. Link to pastebin since SO won’t let me make a post this long.

Answer

The original error originates from creating the custom component GoBackButton, as can be seen from the stack trace, which refers to line 18 of sign-up.fxml (which is just <GoBackButton/>) and subsequently line 18 of GoBackButton.java, which is the loader.load() line.

With the corrected URL for go-back-button.fxml, you get a stack overflow exception as the custom component pattern is incorrectly implemented.

In your code, <GoBackButton/> in sign-up.fxml initiates a call to the GoBackButton constructor. This constructor loads go-back-button.fxml, which has the fx:controller attribute set to GoBackButton, which causes a call to the GoBackButton constructor. This continues recursively, with repeated calls to loader.load() and the constructor.

Instead, you need to set the controller to the current instance of GoBackButton which is being constructed. You do this by omitting the fx:controller attribute in go-back-button.fxml and calling loader.setController(this) before calling loader.load().

Additionally, since the custom component uses a dynamic root (with <fx:root>), you need to explicitly set the root of the FXMLLoader.

The resulting code should be

go-back-button.fxml

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.Button?>
<?import javafx.scene.image.Image?>
<?import javafx.scene.image.ImageView?>

<fx:root mnemonicParsing="false" onAction="#onAction" prefHeight="65.0" prefWidth="98.0" style="-fx-background-color: transparent;" styleClass="go-back-button" type="Button" xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1">
    <graphic>
        <ImageView fitHeight="64.0" fitWidth="48.0" pickOnBounds="true" preserveRatio="true">
            <Image url="@../img/arrow-left.png" />
        </ImageView>
    </graphic>
</fx:root>

and

GoBackButton.java

package org.openjfx.components;

import javafx.fxml.FXML;
import org.openjfx.services.NavigationService;
import javafx.fxml.FXMLLoader;
import javafx.scene.control.Button;

import java.io.IOException;
import java.net.URL;

public class GoBackButton extends Button {
    public GoBackButton() {
        URL url = getClass().getResource("/org/openjfx/fxml/go-back-button.fxml");
        FXMLLoader loader = new FXMLLoader(url);

        try {
            loader.setController(this);
            loader.setRoot(this);
            loader.load();
        } catch (IOException exception) {
            throw new RuntimeException(exception);
        }
    }

    public void onAction() {
        NavigationService.getInstance().pop();
    }
}

Note: I’ve never actually tried setting an onAction handler directly on a fx:root element, but I believe it should work. You can also just do

    public GoBackButton() {
        URL url = getClass().getResource("/org/openjfx/fxml/go-back-button.fxml");
        FXMLLoader loader = new FXMLLoader(url);

        try {
            loader.setController(this);
            loader.setRoot(this);
            loader.load();
            setOnAction(e -> onAction());
        } catch (IOException exception) {
            throw new RuntimeException(exception);
        }
    }

Related Posts

© No Copyrights, All Questions are retrived from public domain.
Tutorial Guruji