Skip to content

Injected vs. GuiceFXMLLoader controller contract #20

@paxbit

Description

@paxbit

Hi headcr4sh,

I'm using fx-guice for a day now. I found it easy to set up but I stumbled upon a behavior I'm not sure I fully understand so far but which would probably be a deal breaker for my current project at hand if it turns out the way I think it is. I'd appreciate it if you could help me understand it.

Is it true and intended that a @FXMLComponent controller always has to be its own root node (extends Node) and that the FXML of such a controller must use an <fx:root> without specifying an fx:controller, because otherwise a javafx.fxml.LoadException: Root value already specified. is thrown? And is it therefore true that FXMLs using an actual Node (like <StackPane ...>) as root and/or specifying a fx:controller attribute can only be loaded using GuiceFXMLLoader, hence never be @Injected?

As far as I can see the former cannot be any different since FXMLComponentMembersInjector supplies the controller instance to both FXMLLoader.setController and FXMLLoader.setRoot in FXMLComponentMembersInjector.injectMembers(...). I'm aware that using <fx:root> along with a component controller of Node is a common way to build reusable components but I'm missing the ability to also inject controllers not following this pattern, which are not a Node and whose FXML root node is not <fx:root> but an actual Node with a fx:controller attribute. Do you think you could implement that, are you interested in doing it or do you think it cannot or should not be done? If so, could you please elaborate why?

My last question targets the exception handling. Do you see any way to actually handle a FXMLLoader specific Exception thrown while injecting (see the Runnable created in FXMLComponentMembersInjector.injectMembers(...)) in user code? Right now, if something goes wrong, you end up with a half initialized injected controller instance with all @FXML fields unbound and still null and without any way to react to the failure. I think it would be very desirable to be able to handle those Exceptions gracefully.
I don't know why but setting a Thread.currentThread().setUncaughtExceptionHandler(...) for the Application Thread did not work out of the box. But that would be a crutch anyway.

Edit: Forgot sth. yesterday. About the limitation, which somewhat impairs productivity, the FXML may not declare a 'fx:controller' when used in conjunction with @Inject because this would cause a javafx.fxml.LoadException: Controller value already specified.: I think using fxmlLoader.setControllerFactory(clazz -> instance) instead of fxmlLoader.setController(instance) in FXMLComponentMembersInjector.injectMembers(...) will safely get around that issue while still allowing allowing IDEs to infer the controller of an FXML. So all the nice inspections and code completions work in the controller and the FXML. Also, SceneBuilder can see the controller.

Thanks for your attention, appreciate your reply, regards,
paxbit

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions