10

I have been experimenting with the FXMLLoader and using the setControllerFactory method using a custom Callback<P,R> implementation.

The ORACLE documentation says the following:

An implementation might return a null value to indicate that it does not or cannot create a controller of the given type; in this case, the default controller construction mechanism will be employed by the loader.

The result I want to achieve is that I can use a dependency injection framework to create any controllers that require parameters but I will let the FXMLLoader load any controllers that do not require parameters.

So if I have the following simple FXML file which uses the ViewController class which accepts no parameters...

<StackPane fx:id="pane"
          xmlns:fx="http://javafx.com/fxml"
          fx:controller="my.package.ViewController">
</StackPane>

and I use the following simple controller factory implementation to signal to the FXMLLoader that I want it to manage the construction of the controller in this case...

loader.setControllerFactory(new Callback<Class<?>, Object>(){
    @Override
    public Object Call(Class<?> type) {
        return null; // Let the FXMLLoader handle construction...
    }
});

after calling the load() method my Initialise method in the ViewController class is never called (I have verified this with a breakpoint).

If I change my controller factory implementation to return an instance of the ViewController class then everything works as expected.

Can anyone help me to clear up my confusion? Am I using the Callback interface incorrectly or is the ORACLE documentation incorrect?

Benjamin Gale
  • 12,977
  • 6
  • 62
  • 100
  • Which version of JavaFX you are using? As the oracle's quoted description says, it may be valid for version 2.1, since the method to override is `getController(Class> type)` in there, while it is `call(Class> param)` in 2.2. So the behavior may also be changed, try with version 2.1. – Uluk Biy Oct 03 '13 at 09:08
  • I'm using version 2.2. I had noticed the difference in the callback syntax but assumed that was all that had changed since there was no mention of it in the 2.2 documentation. It's not a major problem as I can just use the dependency injection framework to create the controllers that do not have parameters in their constructors. – Benjamin Gale Oct 03 '13 at 20:45
  • 1
    Here is [FXMLLoader JavaFX 8 source code](http://hg.openjdk.java.net/openjfx/8/master/rt/file/tip/modules/fxml/src/main/java/javafx/fxml/FXMLLoader.java). Although it is not 2.2 but the most of their codes are similar. The only usage of controllerFactory is `setController(controllerFactory.call(type));`. So it maybe the same in 2.2. Just curious which DI framework are you using? – Uluk Biy Oct 03 '13 at 23:27
  • I'm planning on using Google Guice but I hadn't got that far yet as I was just evaluating the behaviour of the `FXMLLoader` and the controller factory callback. – Benjamin Gale Oct 04 '13 at 07:14
  • if it is null, don't return `null`, instead, return `type.newInstance();`. – Julez Jul 31 '20 at 18:42

1 Answers1

16

javafx does the following in FXMLLoader:

    try {
      if (controllerFactory == null) {
        setController(ReflectUtil.newInstance(type));
      } else {
        setController(controllerFactory.call(type));
      }
    } catch (InstantiationException exception) {
      throw new LoadException(exception);
    } catch (IllegalAccessException exception) {
      throw new LoadException(exception);
    }

so, yes, the oracle tutorial is incorrect.

zhujik
  • 6,514
  • 2
  • 36
  • 43