JavaFx + Google Guice problem

0

Cześć, pozwolę sobie wkleić po angielsku bo podobne pytanie zadałem na stacku, ale póki co żadnej odpowiedzi. Może tutaj ktoś mi pomoże. Wygląda na to, że jak jeden fxml załącza drugi to DI nie działa. Nie rozumiem dlaczego.

I introduced Google Guice to my JavaFx applicatiomn. However I have some problem when I try to @Inject my controller into another controller.

First of all I do:

loader.setControllerFactory(Main.getInjector()::getInstance);
MainController has TopMenuButtonsController included in fxml file:
<fx:include fx:id="topMenuButtons" source="TopMenuButtons.fxml" />

Then I try to load my MainController using FXMLLoader with Guice Controller Factory. TopMenuButtons are initialized automatically because it's included to MainController.

Finally I try to inject MainController into TopMenuButtonsController (because buttons control what to display in MainController:

public class TopMenuButtonsController {

private MainController mainController;

@Inject
public void setMainController(MainController mainController) {
    this.mainController = mainController;
}
@FXML
public void onCreateOrder(ActionEvent event) {
    mainController.setCenter(MainController.CREATE_ORDER_FXML);
}

It succeeds but the instance injected here has all field set to null (@FXML annotation didn't work). I also see that this instance injected here is some different one than I use (different object id)

I can simply make it work by doing this in MainController:

@FXML
private void initialize() {
    topMenuButtonsController.setMainController(this);
}

but my intention was to get rid of such things and use DI. What I can do?

1

W skrócie: obawiam sie że nie da rady. Mieszasz ze sobą dwa zbliżone mechanizmy, oba bazujace na AOP w runtime i classloaderach a to nigdy dobrze się nie kończy.
Możesz spróbować zrobić Inject Guicem do konstruktora obiektu, bo wtedy jest szansa ze kolejność wywołań akurat się dobrze poskłada, ale to trochę long shot, bo wątpie żeby Guice po utworzeniu obiektu poinformował o tym JavęF. Bo widzisz w tym co chcesz zrobić są dwa problemy:

  1. Te wszystkie frameworki nie są magiczne. To że Guice umie coś wstrzyknąć wynika z tego że "zna" wstrzykiwane obiekty bo sam je tworzy. Jak coś innego te obiekty utworzy (np. ty poprzez new, albo jakis inny framework) to Guice już nie pomoże (i odwrotnie, frameowork X nic nie wie o obiektach od Guice). W efekcie mieszane takich 2 mechanizmów to słaby pomysł, bo zwykle albo działa jeden albo drugi, ale nie oba na raz.
  2. Nawet jeśli te dwa frameworki akurat mogą sie spiąć, to pojawia się kwestia kolejności wykonywania AOP i przetwarzania annotacji. Znów - tu nie ma magii! Jest pewna określona kolejność! Albo jedno wykona się wcześniej, albo drugie. W twoim przypadku nawet jeśli to onCreateOrder się wykona, to skąd pewność że wykona się po setMainController a nie przed nim, zaraz po wykonaniu konstruktora?

To co opisałeś na końcu sugeruje że DI JavyFX po prostu stworzył jeszcze jeden obiekt (czyli masz jeden zarządzany przez Guice a drugi przez JavęFX) co ma sens, bo przecież jeden framework wcale nie wie o tym drugim.

0

@Berylo: z tego co wiem Spring można integrowac z JavaFX (jestem pewien na 90%). Być może możesz zmienić Guice na Springa? :)

0

@Shalom
To co piszesz ma sens i też mi się nasuwają takie wnioski. Prawdopodobnie ten child controller jest inicjowany jako pierwszy (kiedy nie ma jeszcze MainController), więc Guice tworzy jego instancje (bez zainicjowanych pól @FXML bo niby jak Guice ma to zrobić). Potem tworzony jest MainController za pośrednictwem JavaFx i wszystkie pola są FXML są poprawnie inicjowane. Dla JavaFx ustawiłem controller factory na guica więc wszyskie controllery powinny być tworzone za pomocą Guica. Nie rozumiem tylko, dlaczego Guice zezwolił na stworzenie MainControllera po raz drugi, skoro już w kontenerze miał jednego (tego utworzonego w child controllerze). Powinien raczej wziąć tego co ma i mu ustawić wszystkie @FXML pola

Spróbuję Springa, ale obawiam się że będzie to samo

0

Zapnij sie debuggerem w konstruktorach i zobacz co się faktycznie dzieje? :)

1

Tutaj jest ciekawy przykład jak pożenić jakiś framework DI i JavaFX: http://www.greggbolinger.com/let-spring-be-your-javafx-controller-factory/

1

Dzięki @scibi92 i @Shalom Ostatecznie wygląda na to, że wszystko robiłem OK, oprócz decyzji o użyciu Google Guice :) Po przesiadce na Springa wszystko działa. Przede wszystkim Spring nie tworzy mi drugiej instancji Controllera tylko inicjuje istniejącą. Na początku faktycznie wstrzykuje instancje z samymi nullami ale potem JavaFx inicjuje poprawnie wszystkie pola @FXML i śmiga elegancko. Google Guice tworzył kolejną instancje zamiast inicjować istniejącą i tu tkwił problem.

1 użytkowników online, w tym zalogowanych: 0, gości: 1