JavaFx + Google Guice problem

Odpowiedz Nowy wątek
2018-12-10 14:39
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?

Pozostało 580 znaków

2018-12-11 09:22

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.


Masz problem? Pisz na forum, nie do mnie. Nie masz problemów? Kup komputer...
edytowany 3x, ostatnio: Shalom, 2018-12-11 09:23
Ja widziałem przykłady jak spiąć JavaFX ze Springiem, a skoro da się ze Springiem to i Guice tez powinno się dać ... - scibi92 2018-12-11 09:42
Nie byłbym tego taki pewien. Spring ma sporo magii do integracji takich rzeczy, np. możesz go spiąć z JSFem i traktować ManagedBeans tak jak beany Springowe, podczas gdy próba zrobienia tego samego z jakimś Guice skończy sie słabo ;] - Shalom 2018-12-11 09:44

Pozostało 580 znaków

2018-12-11 09:46
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? :)


Nie pomagam przez PM. Pytania zadaje się na forum.
Tak zrobię, przetestuję ale obawiam się ze w tym wypadku będzie to samo - Berylo 2018-12-11 10:02

Pozostało 580 znaków

2018-12-11 10:07
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

Pozostało 580 znaków

2018-12-11 10:13
0

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


Masz problem? Pisz na forum, nie do mnie. Nie masz problemów? Kup komputer...
właśnie to;) - Berylo 2018-12-11 10:15

Pozostało 580 znaków

2018-12-11 11:06
1

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


Nie pomagam przez PM. Pytania zadaje się na forum.
Dam znać jak zadziałało - Berylo 2018-12-11 11:13

Pozostało 580 znaków

2018-12-16 21:40
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.

Pozostało 580 znaków

Odpowiedz
Liczba odpowiedzi na stronę

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