3
\$\begingroup\$

The code of my Guice Module looks like this:

public class FXMLModule extends AbstractModule {

    private final Locale locale = Locale.getDefault();
    private final ResourceBundle messages = ResourceBundle.getBundle("i18n.messages", locale);

    @Override
    protected void configure() {
        bind(Controller.class).annotatedWith(MainView.class).to(MainController.class);
        bind(Controller.class).annotatedWith(MovieView.class).to(MovieViewController.class);
    }

    @Provides @MainView
    public FXMLLoader mainViewLoader(@MainView Controller controller) {
        FXMLLoader loader = new FXMLLoader(locate("/jfx/fxml/MainView.fxml"), messages);
        loader.setController(controller);
        return loader;
    }

    @Provides @MovieView
    public FXMLLoader movieViewLoader(@MovieView Controller controller) {
        FXMLLoader loader = new FXMLLoader(locate("/jfx/fxml/MovieView.fxml"), messages);
        loader.setController(controller);
        return loader;
    }

    private URL locate(String location) {
        return getClass().getResource(location);
    }

}

Basically I want to inject fully configured FXMLLoaders into some Controller classes, so that they can work with the root nodes returned from the loaders without having to know anything about other controllers. The MainViewLoader gets injected into the Application class, and the MovieViewLoader gets injected into MainViewController. It works, but I'd have to write a provide method (with almost the same code) for every loader/controller. Any ideas how to make this more generic?

\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

What this is looking for is "Binding by Convention". Since Guice is intended to be as lightweight (and fast) as possible, it does not contain facilities to enable binding by convention.

Neither does Spring for that matter. I think you might be able to automate the bindings injected into the methods if you use Plexus. Do note that none of this will alleviate you from the actual problem you're facing:

Why?

You write:

Basically I want to inject fully configured FXMLLoaders into some Controller classes, so that they can work with the root nodes returned from the loaders without having to know anything about other controllers.

This makes no sense: You're injecting FXMLLoaders into Controllers, specifically into a controller that's not the Controller you set on the FXMLLoader itself. To access the rootNode returned by the loader.

This violates the Law of Demeter. You're grabbing into the responsibilities of another controller.

The solution to this problem is to expose a method on the controller and inject a the controller instance you need, instead of the loader.

This whole module seems to me like it's solving the wrong problem in the first place ...

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.