Why I'm getting javafx.fxml.LoadException even

2019-01-07 00:50发布

问题:

I get

javafx.fxml.LoadException:

When I'm loading and fxml file using following line of code.

AnchorPane anchorPane = (AnchorPane)loader.load()

This is my fxml file excluding import statements.

<AnchorPane prefHeight="537.0" prefWidth="374.0"     xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.buddhikajay.controller.NewTransactionDialogController">
   <children>
      <GridPane hgap="5.0" layoutX="30.0" layoutY="10.0" prefHeight="544.0" prefWidth="314.0" vgap="5.0">
    <columnConstraints>
      <ColumnConstraints hgrow="SOMETIMES" maxWidth="142.0" minWidth="10.0" prefWidth="69.0" />
      <ColumnConstraints hgrow="SOMETIMES" maxWidth="226.0" minWidth="10.0" prefWidth="225.0" />
    </columnConstraints>
    <rowConstraints>
      <RowConstraints maxHeight="70.0" minHeight="10.0" prefHeight="33.0" vgrow="SOMETIMES" />
      <RowConstraints maxHeight="105.0" minHeight="10.0" prefHeight="38.0" vgrow="SOMETIMES" />
      <RowConstraints maxHeight="156.0" minHeight="10.0" prefHeight="51.0" vgrow="SOMETIMES" />
        <RowConstraints maxHeight="154.0" minHeight="10.0" prefHeight="43.0" vgrow="SOMETIMES" />
        <RowConstraints maxHeight="160.0" minHeight="10.0" prefHeight="43.0" vgrow="SOMETIMES" />
        <RowConstraints maxHeight="161.0" minHeight="10.0" prefHeight="63.0" vgrow="SOMETIMES" />
        <RowConstraints maxHeight="301.0" minHeight="10.0" prefHeight="180.0" vgrow="SOMETIMES" />
        <RowConstraints maxHeight="231.0" minHeight="10.0" prefHeight="106.0" vgrow="SOMETIMES" />
    </rowConstraints>
     <padding>
        <Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
     </padding>
     <children>
        <Label text="ID" />
        <Label text="Date" GridPane.rowIndex="1" />
        <Label text="Amont" GridPane.rowIndex="2" />
        <Label text="Person" GridPane.rowIndex="4" />
        <Label text="Type" GridPane.rowIndex="3" />
        <Label text="Resolved" GridPane.rowIndex="5" />
        <Label />
        <Label text="Description" GridPane.rowIndex="6" />
        <TextField fx:id="idTextField" GridPane.columnIndex="1" />
        <TextField fx:id="dateTextField" GridPane.columnIndex="1" GridPane.rowIndex="1" />
        <TextField fx:id="amountTextField" GridPane.columnIndex="1" GridPane.rowIndex="2" />
        <TextArea fx:id="descriptionTextArea" prefHeight="200.0" prefWidth="200.0" GridPane.columnIndex="1" GridPane.rowIndex="6" />
        <HBox maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="50.0" prefWidth="225.0" spacing="20.0" GridPane.columnIndex="1" GridPane.rowIndex="7">
           <GridPane.margin>
              <Insets />
           </GridPane.margin>
           <padding>
              <Insets bottom="10.0" left="20.0" right="10.0" top="10.0" />
           </padding>
           <children>
              <Button fx:id="okButton" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" mnemonicParsing="false" onAction="#okActionFired" prefHeight="25.0" prefWidth="75.0" text="Ok" />
              <Button fx:id="cancleButton" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" mnemonicParsing="false" onAction="#cancleActionFired" prefHeight="25.0" prefWidth="75.0" text="Cancle" />
           </children>
        </HBox>
        <ComboBox fx:id="typeComboBox" prefWidth="150.0" GridPane.columnIndex="1" GridPane.rowIndex="3" />
        <ComboBox fx:id="personComboBox" prefWidth="150.0" GridPane.columnIndex="1" GridPane.rowIndex="4" />
        <ComboBox fx:id="resolvedComboBox" prefWidth="150.0" GridPane.columnIndex="1" GridPane.rowIndex="5" />
     </children>
  </GridPane>
  </children>
</AnchorPane>

The compiler complains that there is an error in line number 1. I'm sure that the path of fxml file is correct. What is wrong with my code?

Here is the full error stack

javafx.fxml.LoadException: 
/C:/Users/Buddhika/Documents/Programming/IdeaProjects/VirtualCreditDesktop/out/production/VirtualCreditDesktop/com/buddhikajay/view/NewTransactionDialog.fxml:9

    at javafx.fxml.FXMLLoader.constructLoadException(FXMLLoader.java:2595)
    at javafx.fxml.FXMLLoader.access$700(FXMLLoader.java:104)
    at javafx.fxml.FXMLLoader$ValueElement.processAttribute(FXMLLoader.java:928)
    at javafx.fxml.FXMLLoader$InstanceDeclarationElement.processAttribute(FXMLLoader.java:967)
    at javafx.fxml.FXMLLoader$Element.processStartElement(FXMLLoader.java:216)
    at javafx.fxml.FXMLLoader$ValueElement.processStartElement(FXMLLoader.java:740)
    at javafx.fxml.FXMLLoader.processStartElement(FXMLLoader.java:2701)
    at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2521)
    at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2435)
    at javafx.fxml.FXMLLoader.load(FXMLLoader.java:2403)
    at com.buddhikajay.controller.NewTransactionDialogController.showNewTransactionDialog(NewTransactionDialogController.java:68)
    at com.buddhikajay.controller.MainApp.start(MainApp.java:51)
    at com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$153(LauncherImpl.java:821)
    at com.sun.javafx.application.LauncherImpl$$Lambda$50/1976027283.run(Unknown Source)
    at com.sun.javafx.application.PlatformImpl.lambda$runAndWait$166(PlatformImpl.java:323)
    at com.sun.javafx.application.PlatformImpl$$Lambda$46/301541210.run(Unknown Source)
    at com.sun.javafx.application.PlatformImpl.lambda$null$164(PlatformImpl.java:292)
    at com.sun.javafx.application.PlatformImpl$$Lambda$48/474926796.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at com.sun.javafx.application.PlatformImpl.lambda$runLater$165(PlatformImpl.java:291)
    at com.sun.javafx.application.PlatformImpl$$Lambda$47/1662429848.run(Unknown Source)
    at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
    at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
    at com.sun.glass.ui.win.WinApplication.lambda$null$141(WinApplication.java:102)
    at com.sun.glass.ui.win.WinApplication$$Lambda$38/519284171.run(Unknown Source)
    at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.InstantiationException: com.buddhikajay.controller.NewTransactionDialogController
    at java.lang.Class.newInstance(Class.java:423)
    at sun.reflect.misc.ReflectUtil.newInstance(ReflectUtil.java:51)
    at javafx.fxml.FXMLLoader$ValueElement.processAttribute(FXMLLoader.java:923)
    ... 23 more
Caused by: java.lang.NoSuchMethodException: com.buddhikajay.controller.NewTransactionDialogController.<init>()
    at java.lang.Class.getConstructor0(Class.java:3074)
    at java.lang.Class.newInstance(Class.java:408)
    ... 25 more

回答1:

The problem is described in the stack trace:

Caused by: java.lang.NoSuchMethodException: com.buddhikajay.controller.NewTransactionDialogController.()

which basically says your controller class doesn't have a zero-argument constructor.

By default, the FXMLLoader will create the controller by calling its zero-argument constructor. Remove the constructor that you have defined in the controller class, or remove the parameters that it takes.

If you really need to pass arguments to the controller's constructor, you can either create the controller in Java code and pass it to the FXMLLoader:

NewTransactionDialogController controller = new NewTransactionDialogController(someValue);
FXMLLoader loader = new FXMLLoader();
loader.setLocation(...);
loader.setController(controller);
AnchorPane anchorPane = loader.load();

(Using this code, you must remove the fx:controller attribute from the FXML.)

Or, set a controller factory:

FXMLLoader loader = new FXMLLoader();
loader.setLocation(...);
loader.setControllerFactory(clazz -> {
    if (clazz == NewTransactionDialogController.class) {
        return new NewTransactionDialogController(someValue);
    } else {
        // default behavior:
        try {
            return clazz.newInstance();
        } catch (Exception exc) {
            throw new RuntimeException(exc);
        }
    }
});

AnchorPane anchorPane = loader.load();

(In this version, leave the fx:controller attribute in the FXML file.)



回答2:

I was about to enter a different question as remarked by @James_D for my comment because Until I Read the first line of the FXML on this question, I had thought that I had a different problem.

For my sins, I reduced the challenge to a simple example of a single controller and two FXML files. One worked and the second fail/failed.

The starting point is the Netbeans sample "[Click me!]" sample. The code is pasted below. And, first a solution.

As preamble, let me say that it seems that everyone has been blaming the Java controller for these load errors. I had a bunch of errors like this on a project a couple of years ago. We exhausted "controller" debugging and eventually pressed-forward by re-building the FXML screens with ScendBuilder. I didn't have time to investigate further then.

Last week I perfectly working FXML screen started failing to load because we moved it to a runtime directory (previously it was in the JAR resources area).

KLUNK!

After 3 or 4 days tweaking that and this, I made a comment here on my error:

  • unknown path: 7
  • Javafx fxml LoadException: Error resolving onAction='#handleButtonAction', either the event handler is not in the Namespace or there is an error in the script.

On only the "simple.fxml" file, but not the "Scene.fxml" file. The file "simple.fxml" is reduced from the app FXML file that initially gave the problem. There were too many variables on that original file, so chop-chop-chop to match the canned demo.

When you use ONLY this:

xmlns:fx="http://javafx.com/fxml"

FXML load-s from files on disk under in your application folder work just like you want them to (well, like I want, anyway). Looking at the FXML above it is using a more 'fragile' namespace, viz.

Queston's original FXML:

  <AnchorPane ...
              xmlns="http://javafx.com/javafx/8" 
              xmlns:fx="http://javafx.com/fxml/1" ... >

By using diff, I slowly morphed "simple.fxml" to be as close as possible to "Scene.fxml", and "simple" just keeps failing to load. Please note; always using the same controller

Loading FXML with other metadata has not worked consistently an FXML file was moved. I don't have an explanation as to how this is so.

The FXML is kept in a directory called "test/resources/fxml/simple.fxml" for example. When I was building with both files in the project JAR, the 'same' FXML in both cases loaded and worked as expected. To me there's something un-said about aspects of the file load precess. Again for me, this is undesirable because the KEY value of a external scene definition would be interchange.

These kind of bear traps in XML mark-up that are (apparently) not picked up by development tools like SceneBuilder or the FXMLLoader() are barriers to progress on live projects that don't have slack to investigate esoteric weirdness like this.

This is witnessed by our previous project experience -- I was easier to re-edit a complex screen with SceneBuilder as a whole than track down load problems like this one. The call to action is: Diagnostics on FXML load -- an FXML Lint would be almost a requirement.


Controller, SimpleController.java:

  package ex.view.views;

  import java.net.URL;
  import java.util.ResourceBundle;
  import javafx.event.ActionEvent;
  import javafx.fxml.FXML;
  import javafx.fxml.Initializable;
  import javafx.scene.control.Label;

  public class SimpleController implements Initializable {

      @FXML
      private Label label;

      @FXML
      private void handleButtonAction(ActionEvent event) {
          System.out.println("You clicked me!");
          label.setText("Hello World!");
      }

      @Override
      public void initialize(URL url, ResourceBundle rb) {
          // TODO
      }    
  }

The failing FXML started life as one of the Maven archetypes (I think) and that file worked fine until I moved the FXML files to a folder and loaded them from a InputStream.

I have formatted the AnchorPane markup on multiple lines for readability.

simple.fxml:

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

  <?import javafx.scene.control.Button?>
  <?import javafx.scene.control.Label?>
  <?import javafx.scene.layout.AnchorPane?>

  <AnchorPane id="AnchorPane" prefHeight="200" prefWidth="320" 
              xmlns="http://javafx.com/javafx/8.0.65" 
              xmlns:fx="http://javafx.com/fxml/1"
               fx:controller="ex.view.views.SimpleController">
      <children>
          <Button fx:id="button" layoutX="126" layoutY="90" text="Click Me!" />
          <Label fx:id="label" layoutX="126" layoutY="120" minHeight="16" minWidth="69" />
      </children>
  </AnchorPane>

The working FXML mark-up is from the Netbeans 8.1 samples.

Scene.fxml:

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

  <?import java.lang.*?>
  <?import java.util.*?>
  <?import javafx.scene.*?>
  <?import javafx.scene.control.*?>
  <?import javafx.scene.layout.*?>

  <AnchorPane id="AnchorPane" prefHeight="200" prefWidth="320" 
              xmlns:fx="http://javafx.com/fxml" 
              fx:controller="ex.view.views.SimpleController">
      <children>
          <Button layoutX="126" layoutY="90" text="Click Me!" onAction="#handleButtonAction" fx:id="button" />
          <Label layoutX="126" layoutY="120" minHeight="16" minWidth="69" fx:id="label" />
      </children>
  </AnchorPane>