0

I'm creating a dashboard for a management system using JavaFX. Also, i'm using an MVC pattern.

I'm having troubles dealing with dependency injection: my main problem was that my HomepageView contains an HomepageController variable, and on the other side HomepageController contains an HomepageView.

So, i tried with DI using constructors, but it would be cyclical so i gave up and tried DI using Setters. So, i have a Main class, and in the start method i instantiate the 2 classes using the default constructor and set each others variables. This is my main code:

public class Main extends Application {

    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage stage) throws IOException {


        FXMLLoader fxmlLoader = new FXMLLoader(HomepageView.class.getResource("/homepage/homepage.fxml"));
        Scene scene = new Scene(fxmlLoader.load());
        stage.setTitle("Hello!");
        stage.setScene(scene);
        stage.show();


        HomepageController homeController = new HomepageController();
        HomepageView homeView = new HomepageView();
        PersonalizzaMenuController personalizzaController = new PersonalizzaMenuController();
        PersonalizzaMenuView personalizzaView = new PersonalizzaMenuView();
        
        personalizzaController.setPersonalizzaMenu(personalizzaView);
        personalizzaView.setPersonalizzaMenuController(personalizzaController);
        homeView.setHomepageController(homeController);
        homeController.setHomepageControllers(homeView, personalizzaView);

    }
}

This is my Homepage view class:

 package com.example.ratatouille23.homepage;

import com.example.ratatouille23.Model.Utente;
import com.example.ratatouille23.View;
import com.example.ratatouille23.View2;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;

import java.io.IOException;

public class HomepageView {

    @FXML
    BorderPane borderPane;
    @FXML
    Label labelUsername;

    private Stage stage;
    private Scene scene;
    private Parent root;

    private String nomeNodo = "HomePage";

    private HomepageController homepageController;

    // *********************

    public HomepageView(){};

    @FXML
    public void initialize(){
        labelUsername.setText(Utente.getUsername());
    }

    //************************

    // Action event

    public void clickPulsantePersonalizzaMenu(){
        homepageController.onPersonalizzaMenuClicked();
    }


    @Override
    public Node loadNode() throws IOException {
        return FXMLLoader.load(getClass().getResource("/homepage/homepage.fxml"));
    }

    public void setHomepageController(HomepageController homepageController) {
        this.homepageController = homepageController;
    }
}

And this is my HomepageController class:

package com.example.ratatouille23.homepage;

import com.example.ratatouille23.View;
import com.example.ratatouille23.creaUtente.CreaUtenteView;
import com.example.ratatouille23.inserisciAvvisi.InserisciAvvisiView;
import com.example.ratatouille23.personalizzaMenu.NuovoPiattoView;
import com.example.ratatouille23.personalizzaMenu.PersonalizzaMenuView;
import javafx.scene.Node;
import javafx.scene.control.Alert;
import javafx.scene.control.ButtonType;
import javafx.scene.layout.BorderPane;

import java.io.IOException;
import java.util.Optional;

public class HomepageController {

    HomepageView homepage;
    PersonalizzaMenuView personalizzaMenu;

    //**************************

    // Costruttori

    HomepageController(){};


    //**************************

    // On Action Event


    public void onPersonalizzaMenuClicked() {
           try {
            setBorderPaneCenter(personalizzaMenu.loadNode());
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }



 
    //**************************

    // Metodi di utility

    public void setBorderPaneCenter(Node node){
        homepage.borderPane.getChildren().remove(homepage.borderPane.getCenter());
        homepage.borderPane.setCenter(node);
    }

    public void setBorderPaneRight(Node node){
       homepage.borderPane.getChildren().remove(homepage.borderPane.getRight());
        homepage.borderPane.setCenter(node);
    }

    public void setHomepageControllers(HomepageView home, PersonalizzaMenuView personalizzamenu){
        this.homepage = home;
        this.personalizzaMenu = personalizzamenu;
       }

}

Homepage FXML:

<?xml version="1.0" encoding="UTF-8"?>

<?import de.jensd.fx.glyphs.fontawesome.FontAwesomeIconView?>
<?import java.lang.String?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.text.Font?>

<BorderPane fx:id="borderPane" xmlns="http://javafx.com/javafx/19" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.example.ratatouille23.homepage.HomepageView">
   <left>
      <AnchorPane prefHeight="700.0" prefWidth="306.0" BorderPane.alignment="CENTER">
         <children>
            <AnchorPane layoutX="18.0" layoutY="279.0" prefHeight="421.0" prefWidth="277.0" stylesheets="@homepage.css">
               <styleClass>
                  <String fx:value="nav-2" />
                  <String fx:value="shadow" />
               </styleClass>
               <children>
                  <Button layoutX="19.0" layoutY="21.0" mnemonicParsing="false" onAction="#clickPulsanteInserisciAvvisi" prefHeight="40.0" prefWidth="240.0" styleClass="nav-btn" stylesheets="@homepage.css" text="Inserisci Avvisi" />
                  <Button fx:id="buttonPersonalizzaMenu" layoutX="20.0" layoutY="89.0" mnemonicParsing="false" onAction="#clickPulsantePersonalizzaMenu" prefHeight="40.0" prefWidth="240.0" styleClass="nav-btn" stylesheets="@homepage.css" text="Personalizza Menu" />
                  <Button fx:id="buttonCreaUtente" layoutX="21.0" layoutY="158.0" mnemonicParsing="false" onAction="#clickPulsanteCreaUtente" prefHeight="40.0" prefWidth="240.0" styleClass="nav-btn" stylesheets="@homepage.css" text="Crea Utente" />
                  <Button layoutX="23.0" layoutY="372.0" mnemonicParsing="false" prefHeight="34.0" prefWidth="41.0" styleClass="signout" stylesheets="@homepage.css">
                     <graphic>
                        <FontAwesomeIconView glyphName="SIGN_OUT" size="2em" wrappingWidth="20.861303329467773" />
                     </graphic>
                  </Button>
                  <Label layoutX="75.0" layoutY="372.0" text="Log out">
                     <font>
                        <Font name="Al Nile" size="18.0" />
                     </font>
                  </Label>
               </children>
            </AnchorPane>
            <AnchorPane layoutX="18.0" prefHeight="253.0" prefWidth="277.0" stylesheets="@homepage.css">
               <children>
                  <FontAwesomeIconView fill="WHITE" glyphName="USER" layoutX="116.0" layoutY="63.0" size="60" />
                  <Label layoutX="78.0" layoutY="90.0" text="Benvenuto," textFill="WHITE">
                     <font>
                        <Font name="Tahoma" size="24.0" />
                     </font>
                  </Label>
                  <Label fx:id="labelUsername" layoutX="87.0" layoutY="124.0" text="UTENTE" textFill="WHITE">
                     <font>
                        <Font name="Al Nile" size="24.0" />
                     </font>
                  </Label>
               </children>
               <styleClass>
                  <String fx:value="shadow" />
                  <String fx:value="nav-1" />
               </styleClass>
            </AnchorPane>
         </children>
      </AnchorPane>
   </left>
   <top>
      <AnchorPane prefHeight="41.0" prefWidth="1100.0" BorderPane.alignment="CENTER" />
   </top>
   <right>
      <AnchorPane prefHeight="700.0" prefWidth="343.0" BorderPane.alignment="CENTER" />
   </right>
   <center>
      <AnchorPane maxWidth="-Infinity" minWidth="-Infinity" prefHeight="700.0" prefWidth="453.0" stylesheets="@homepage.css" BorderPane.alignment="CENTER" />
   </center>
</BorderPane>

This is PersonalizzaMenuView:

package com.example.ratatouille23.personalizzaMenu;

import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Node;
import javafx.scene.control.*;
import javafx.scene.layout.AnchorPane;

import java.io.IOException;
import java.util.Optional;

public class PersonalizzaMenuView {

   @FXML
   Accordion listaCategorie;

   PersonalizzaMenuController personalizzaMenuController;

   public PersonalizzaMenuView(){};


   // Carica nodo schermata
   public Node caricaNodoPersonalizzaMenu() throws IOException {
       FXMLLoader loader = new FXMLLoader(getClass().getResource("/personalizzaMenu/personalizza-menu.fxml"));
       return loader.load();
   }



   public void setPersonalizzaMenuController(PersonalizzaMenuController personalizzaMenuController) {
       this.personalizzaMenuController = personalizzaMenuController;
   }
}

PersonalizzaMenuController:

package com.example.ratatouille23.personalizzaMenu;

import javafx.scene.control.Label;
import javafx.scene.control.TextInputDialog;
import javafx.scene.control.TitledPane;
import javafx.scene.layout.AnchorPane;

import java.util.Optional;

public class PersonalizzaMenuController {

   PersonalizzaMenuView personalizzaMenu;

   public PersonalizzaMenuController(PersonalizzaMenuView personalizzamenu){
       this.personalizzaMenu = personalizzamenu;
   }

   public PersonalizzaMenuController(){};

   public void onPulsanteAggiungiCategoriaClicked() {
       //
   }

        */
   }

   public void setPersonalizzaMenu(PersonalizzaMenuView personalizzaMenu) {
       this.personalizzaMenu = personalizzaMenu;
   }
}

PersonalizzaMenu FXML:

<?xml version="1.0" encoding="UTF-8"?>

<?import java.lang.String?>
<?import javafx.scene.control.Accordion?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.ScrollPane?>
<?import javafx.scene.control.TitledPane?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.text.Font?>

<BorderPane minHeight="-Infinity" minWidth="-Infinity" prefHeight="682.0" prefWidth="500.0" styleClass="white-bg" stylesheets="@../homepage/homepage.css" xmlns="http://javafx.com/javafx/19" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.example.ratatouille23.personalizzaMenu.PersonalizzaMenuView">
  <bottom>
     <HBox alignment="CENTER" prefHeight="129.0" prefWidth="500.0" spacing="60.0">
        <children>
           <Button mnemonicParsing="false" onAction="#clickPulsantePiu" styleClass="signout" stylesheets="@../homepage/homepage.css" text="+ Aggiungi Categoria" textFill="WHITE">
              <font>
                 <Font name="Tahoma" size="13.0" />
              </font>
           </Button>
           <Button mnemonicParsing="false" onAction="#clickPulsanteAggiungiPiatto" text="+ Aggiungi piatto" />
           <Button mnemonicParsing="false" text="- Elimina" />
        </children>
     </HBox>
  </bottom>
  <top>
     <HBox alignment="CENTER" prefHeight="130.0" prefWidth="500.0" stylesheets="@../homepage/homepage.css" BorderPane.alignment="CENTER">
        <styleClass>
           <String fx:value="nav-1" />
           <String fx:value="shadow" />
        </styleClass>
        <children>
           <Label alignment="TOP_CENTER" contentDisplay="TOP" text="PERSONALIZZA MENU" textAlignment="CENTER" textFill="WHITE">
              <font>
                 <Font name="Tahoma" size="29.0" />
              </font>
           </Label>
        </children>
     </HBox>
  </top>
  <center>
     <ScrollPane fitToHeight="true" fitToWidth="true" hbarPolicy="NEVER" prefHeight="200.0" prefWidth="200.0" BorderPane.alignment="CENTER">
        <content>
           <VBox prefHeight="200.0" prefWidth="100.0">
              <children>
                 <Accordion fx:id="listaCategorie">
                   <panes>
                       <TitledPane animated="true" text="untitled">
                          <content>
                             <VBox prefHeight="118.0" prefWidth="462.0" />
                          </content>
                       </TitledPane>
                   </panes>
                 </Accordion>
              </children>
           </VBox>
        </content>
     </ScrollPane>
  </center>
</BorderPane>

When i run the main method, the homepage starts, but whenever i press a button that should load another window this is the error:

mar 21, 2023 5:50:44 PM com.sun.glass.ui.mac.MacApplication lambda$waitForReactivation$6
WARNING: Timeout while waiting for app reactivation
Exception in thread "JavaFX Application Thread" java.lang.RuntimeException: java.lang.reflect.InvocationTargetException
    at javafx.fxml@19/javafx.fxml.FXMLLoader$MethodHandler.invoke(FXMLLoader.java:1857)
    at javafx.fxml@19/javafx.fxml.FXMLLoader$ControllerMethodEventHandler.handle(FXMLLoader.java:1724)
    at javafx.base@19/com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:86)
    at javafx.base@19/com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:234)
    at javafx.base@19/com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
    at javafx.base@19/com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
    at javafx.base@19/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
    at javafx.base@19/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at javafx.base@19/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
    at javafx.base@19/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at javafx.base@19/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
    at javafx.base@19/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at javafx.base@19/com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
    at javafx.base@19/com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:49)
    at javafx.base@19/javafx.event.Event.fireEvent(Event.java:198)
    at javafx.graphics@19/javafx.scene.Node.fireEvent(Node.java:8923)
    at javafx.controls@19/javafx.scene.control.Button.fire(Button.java:203)
    at javafx.controls@19/com.sun.javafx.scene.control.behavior.ButtonBehavior.mouseReleased(ButtonBehavior.java:207)
    at javafx.controls@19/com.sun.javafx.scene.control.inputmap.InputMap.handle(InputMap.java:274)
    at javafx.base@19/com.sun.javafx.event.CompositeEventHandler$NormalEventHandlerRecord.handleBubblingEvent(CompositeEventHandler.java:247)
    at javafx.base@19/com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:80)
    at javafx.base@19/com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:234)
    at javafx.base@19/com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
    at javafx.base@19/com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
    at javafx.base@19/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
    at javafx.base@19/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at javafx.base@19/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
    at javafx.base@19/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at javafx.base@19/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
    at javafx.base@19/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at javafx.base@19/com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
    at javafx.base@19/com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:54)
    at javafx.base@19/javafx.event.Event.fireEvent(Event.java:198)
    at javafx.graphics@19/javafx.scene.Scene$MouseHandler.process(Scene.java:3894)
    at javafx.graphics@19/javafx.scene.Scene.processMouseEvent(Scene.java:1887)
    at javafx.graphics@19/javafx.scene.Scene$ScenePeerListener.mouseEvent(Scene.java:2620)
    at javafx.graphics@19/com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:411)
    at javafx.graphics@19/com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:301)
    at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
    at javafx.graphics@19/com.sun.javafx.tk.quantum.GlassViewEventHandler.lambda$handleMouseEvent$2(GlassViewEventHandler.java:450)
    at javafx.graphics@19/com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(QuantumToolkit.java:424)
    at javafx.graphics@19/com.sun.javafx.tk.quantum.GlassViewEventHandler.handleMouseEvent(GlassViewEventHandler.java:449)
    at javafx.graphics@19/com.sun.glass.ui.View.handleMouseEvent(View.java:551)
    at javafx.graphics@19/com.sun.glass.ui.View.notifyMouse(View.java:937)
    at javafx.graphics@19/com.sun.glass.ui.mac.MacView.notifyMouse(MacView.java:127)
Caused by: java.lang.reflect.InvocationTargetException
    at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:116)
    at java.base/java.lang.reflect.Method.invoke(Method.java:578)
    at com.sun.javafx.reflect.Trampoline.invoke(MethodUtil.java:77)
    at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
    at java.base/java.lang.reflect.Method.invoke(Method.java:578)
    at javafx.base@19/com.sun.javafx.reflect.MethodUtil.invoke(MethodUtil.java:275)
    at javafx.fxml@19/com.sun.javafx.fxml.MethodHelper.invoke(MethodHelper.java:84)
    at javafx.fxml@19/javafx.fxml.FXMLLoader$MethodHandler.invoke(FXMLLoader.java:1854)
    ... 44 more
Caused by: java.lang.NullPointerException: Cannot invoke "com.example.ratatouille23.homepage.HomepageController.onInserisciAvvisiClicked()" because "this.homepageController" is null
    at com.example.ratatouille23/com.example.ratatouille23.homepage.HomepageView.clickPulsanteInserisciAvvisi(HomepageView.java:54)
    at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
    ... 51 more

This sounds strange to me, because i used the setter methods, so the HomepageController should not be null.

I hope i gave all the useful informations. I'm also sure i probably not quite understood the right way to use this approach.

Ric97
  • 109
  • 1
  • 6
  • 1
    Create and post a [mre]. The bottom line here is that none of the structure you create (all the views and controllers you instantiate) seem to have anything to do with what is actually displayed, which is loaded from an FXML file. There is no connection at all between the FXML file (which you haven't shown) and the objects you create. But I don't see any way to answer this without a complete MRE. – James_D Mar 21 '23 at 16:54
  • I think that to create a minimal reproducible example i must post every class i created, that's why i omitted them and only posted the interested classes. I will add another 2 classes so that maybe it could be more complete – Ric97 Mar 21 '23 at 16:57
  • 1
    No, please actually create a [mre]. Read the link to understand what is required. Are you seriously trying to argue that your application needs **five** view classes and **five** controller classes, and who knows what else that you haven't shown, in order to reproduce the issue? – James_D Mar 21 '23 at 16:58
  • 1
    controllers have to be __loaded__ (not instantiated) to inject their fields – kleopatra Mar 21 '23 at 17:02
  • 1
    Does this answer your question? [JavaFX, Label null pointer exception](https://stackoverflow.com/questions/36186907/javafx-label-null-pointer-exception) – kleopatra Mar 21 '23 at 17:02
  • @James_D I answered before you edited your comment giving advice on what should be changed. I hope now it's better. – Ric97 Mar 21 '23 at 17:14
  • @kleopatra i'll look into the link you posted. My main difficulty right now is that my 'View' is actually the JavaFX's controller (i modified this after a discussion on here some days ago) so i'm having troubles on dealing with this. – Ric97 Mar 21 '23 at 17:15
  • It's also really unclear what you are gaining from all this additional complexity. If the idea is to implement a "classical MVC architecture" as discussed in your [previous question](https://stackoverflow.com/questions/75769325/javafxs-controller-is-different-from-the-mvcs-controller), then you really haven't achieved it here. I'm assuming your "View" classes are the "FXML controllers", and that you controller classes are the "MVC controllers". But in that case, your view should be self-contained. Your controllers have intimate details of the layout (view), which defeats your entire purpose. – James_D Mar 21 '23 at 17:15
  • You are initializing the `homepageController` field in the instance of `HomepageView` that you create by hand (i.e. by `HomepageView homeView = new HomepageView();`). The `homepageController` field in the instance of `HomepageView` that is created by the `FXMLLoader` when you load the FXML is never initialized, so it is still null, and consequently you get a null pointer exception. – James_D Mar 21 '23 at 17:18
  • @James_D Can you explain further what you mean with ''your controllers have intimate details of the layout''? My controllers only contain a reference to the view so they can interact with it, and the logic for what should happen when you click buttons. – Ric97 Mar 21 '23 at 17:19
  • @James_D Ok, that's what i thought was going on: when i create a 'new' View, it is different from the view 'loaded' by the fxml, thus not having set a controller. Makes sense. How could i fix this? – Ric97 Mar 21 '23 at 17:20
  • You have code like `homepage.borderPane.setCenter(...)` in your controller. That *explicitly* relies on the layout in the view using a `BorderPane`, and even goes as far as to make the fields in the view non-private (which is just bad practice without even thinking about UI architectures). So you have a very tight coupling between the view and controller; you can't, for example, change the layout strategy in the view without changing the controller code. So your view is not self-contained. – James_D Mar 21 '23 at 17:23
  • If you insist on using this architecture, which I think is nonsense, you need to get a reference to the controller created by the `FXMLLoader` instead of creating an instance yourself. – James_D Mar 21 '23 at 17:24
  • Thank you for your comments. I'll try to make this work better with your advices. I'm sorry it is nonsense to you. I have to do this for a university project so some things are streamlined (the MVC pattern and how i should organize it), the rest is me trying to make new things work. So no, i don't insist on using this architecture, but i don't know how could i make this from the ground up in a better way. – Ric97 Mar 21 '23 at 17:30
  • An extra question: to make the view self contained, should i then put the 'homepage.borderpane.setCenter' methods in the View (and not in the Controller)? – Ric97 Mar 21 '23 at 17:39
  • 1
    [Here](https://stackoverflow.com/questions/36868391/using-javafx-controller-without-fxml/36873768#36873768) is my interpretation of MVC (for a very simple example). It doesn't use FXML, but to make that change you'd replace the `View` class with an FXML and "FXML-controller" pair. Note the controller doesn't reference the view at all. Nothing "tells the view what to do"; it just observes the model and responds to changes in it. – James_D Mar 21 '23 at 17:42
  • If you want to use dependency injection, I suggest using an off-the-shelf implementation rather than rolling your own. If you want no additional dependencies then consider [Eden dependency injection](https://edencoding.com/dependency-injection/). If you want a general purpose dependency injection system, then there is stuff like [gluon ignite](https://gluonhq.com/labs/ignite/), or the more heavyweight [fxweaver](https://github.com/rgielen/javafx-weaver) or [spring context injection](https://stackoverflow.com/questions/57887944/adding-spring-dependency-injection-in-javafx-jpa-repo-service). – jewelsea Mar 21 '23 at 23:37

0 Answers0