FX 11: Controller loading in Baseclass












2















Injecting FXML into a derived FX Class(Controller) from the base class works - but why?



The code below is actually working. But i am curious why?



The FXML is loaded in the constructor of the abstract Base class (FXMLPopup) and injected to the derived class(TestfxmlController).



My problem: when the base class is constructed(and the fxml gets injected) the derived class hasn't been constructed yet.
Also imho the base shouldn't know anything about the derived class, should it?



Further the field, that is to be injected is private in the derived class! So the loader has to make it accessible but there is no @FXML in the base that would give permision to do so(permision is given only in the derived class that hasn't yet been constructed - Well the Field doesn't exist at all in the base!).



Still the FXML gets correctly injected into the derived class - and the fields are actually the ones in the derived class. Why does this work?



Baseclass:



public abstract class FXMLPopup extends Popup implements Initializable {

@SuppressWarnings("LeakingThisInConstructor")
public FXMLPopup(String filename) {
super();
final FXMLLoader loader = new FXMLLoader(FXMLLoader.class.getResource(filename));
//if a controller is set in the fxml, ignor it.
loader.setControllerFactory(p -> this);
try {
this.getContent().add(loader.load());
} catch (IOException ex) { }
}
}


Derived class:



public class TestfxmlController extends FXMLPopup {

@FXML
private ChoiceBox<String> testChoiceBox;

public TestfxmlController() {
super("fxml/testfxml.fxml");
}

@Override
public void initialize(URL url, ResourceBundle rb) {
//works!!!!
testChoiceBox.getItems().add("test");
}
}


FXMLCode:



<AnchorPane id="AnchorPane" prefHeight="400.0" prefWidth="600.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/11.0.1" fx:controller="TestfxmlController">
<children>
<ChoiceBox fx:id="testChoiceBox" layoutX="113.0" layoutY="160.0" prefWidth="150.0" />
</children>
</AnchorPane>


What would I expect? I would expect Errors over errors. That the loader doesn't find the fields in the base class and that access is denied....
But it somehow magicaly works flawless. Despite I am violating like everything possible in such a small example. I'd like to understand the "magic" behind this...










share|improve this question





























    2















    Injecting FXML into a derived FX Class(Controller) from the base class works - but why?



    The code below is actually working. But i am curious why?



    The FXML is loaded in the constructor of the abstract Base class (FXMLPopup) and injected to the derived class(TestfxmlController).



    My problem: when the base class is constructed(and the fxml gets injected) the derived class hasn't been constructed yet.
    Also imho the base shouldn't know anything about the derived class, should it?



    Further the field, that is to be injected is private in the derived class! So the loader has to make it accessible but there is no @FXML in the base that would give permision to do so(permision is given only in the derived class that hasn't yet been constructed - Well the Field doesn't exist at all in the base!).



    Still the FXML gets correctly injected into the derived class - and the fields are actually the ones in the derived class. Why does this work?



    Baseclass:



    public abstract class FXMLPopup extends Popup implements Initializable {

    @SuppressWarnings("LeakingThisInConstructor")
    public FXMLPopup(String filename) {
    super();
    final FXMLLoader loader = new FXMLLoader(FXMLLoader.class.getResource(filename));
    //if a controller is set in the fxml, ignor it.
    loader.setControllerFactory(p -> this);
    try {
    this.getContent().add(loader.load());
    } catch (IOException ex) { }
    }
    }


    Derived class:



    public class TestfxmlController extends FXMLPopup {

    @FXML
    private ChoiceBox<String> testChoiceBox;

    public TestfxmlController() {
    super("fxml/testfxml.fxml");
    }

    @Override
    public void initialize(URL url, ResourceBundle rb) {
    //works!!!!
    testChoiceBox.getItems().add("test");
    }
    }


    FXMLCode:



    <AnchorPane id="AnchorPane" prefHeight="400.0" prefWidth="600.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/11.0.1" fx:controller="TestfxmlController">
    <children>
    <ChoiceBox fx:id="testChoiceBox" layoutX="113.0" layoutY="160.0" prefWidth="150.0" />
    </children>
    </AnchorPane>


    What would I expect? I would expect Errors over errors. That the loader doesn't find the fields in the base class and that access is denied....
    But it somehow magicaly works flawless. Despite I am violating like everything possible in such a small example. I'd like to understand the "magic" behind this...










    share|improve this question



























      2












      2








      2








      Injecting FXML into a derived FX Class(Controller) from the base class works - but why?



      The code below is actually working. But i am curious why?



      The FXML is loaded in the constructor of the abstract Base class (FXMLPopup) and injected to the derived class(TestfxmlController).



      My problem: when the base class is constructed(and the fxml gets injected) the derived class hasn't been constructed yet.
      Also imho the base shouldn't know anything about the derived class, should it?



      Further the field, that is to be injected is private in the derived class! So the loader has to make it accessible but there is no @FXML in the base that would give permision to do so(permision is given only in the derived class that hasn't yet been constructed - Well the Field doesn't exist at all in the base!).



      Still the FXML gets correctly injected into the derived class - and the fields are actually the ones in the derived class. Why does this work?



      Baseclass:



      public abstract class FXMLPopup extends Popup implements Initializable {

      @SuppressWarnings("LeakingThisInConstructor")
      public FXMLPopup(String filename) {
      super();
      final FXMLLoader loader = new FXMLLoader(FXMLLoader.class.getResource(filename));
      //if a controller is set in the fxml, ignor it.
      loader.setControllerFactory(p -> this);
      try {
      this.getContent().add(loader.load());
      } catch (IOException ex) { }
      }
      }


      Derived class:



      public class TestfxmlController extends FXMLPopup {

      @FXML
      private ChoiceBox<String> testChoiceBox;

      public TestfxmlController() {
      super("fxml/testfxml.fxml");
      }

      @Override
      public void initialize(URL url, ResourceBundle rb) {
      //works!!!!
      testChoiceBox.getItems().add("test");
      }
      }


      FXMLCode:



      <AnchorPane id="AnchorPane" prefHeight="400.0" prefWidth="600.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/11.0.1" fx:controller="TestfxmlController">
      <children>
      <ChoiceBox fx:id="testChoiceBox" layoutX="113.0" layoutY="160.0" prefWidth="150.0" />
      </children>
      </AnchorPane>


      What would I expect? I would expect Errors over errors. That the loader doesn't find the fields in the base class and that access is denied....
      But it somehow magicaly works flawless. Despite I am violating like everything possible in such a small example. I'd like to understand the "magic" behind this...










      share|improve this question
















      Injecting FXML into a derived FX Class(Controller) from the base class works - but why?



      The code below is actually working. But i am curious why?



      The FXML is loaded in the constructor of the abstract Base class (FXMLPopup) and injected to the derived class(TestfxmlController).



      My problem: when the base class is constructed(and the fxml gets injected) the derived class hasn't been constructed yet.
      Also imho the base shouldn't know anything about the derived class, should it?



      Further the field, that is to be injected is private in the derived class! So the loader has to make it accessible but there is no @FXML in the base that would give permision to do so(permision is given only in the derived class that hasn't yet been constructed - Well the Field doesn't exist at all in the base!).



      Still the FXML gets correctly injected into the derived class - and the fields are actually the ones in the derived class. Why does this work?



      Baseclass:



      public abstract class FXMLPopup extends Popup implements Initializable {

      @SuppressWarnings("LeakingThisInConstructor")
      public FXMLPopup(String filename) {
      super();
      final FXMLLoader loader = new FXMLLoader(FXMLLoader.class.getResource(filename));
      //if a controller is set in the fxml, ignor it.
      loader.setControllerFactory(p -> this);
      try {
      this.getContent().add(loader.load());
      } catch (IOException ex) { }
      }
      }


      Derived class:



      public class TestfxmlController extends FXMLPopup {

      @FXML
      private ChoiceBox<String> testChoiceBox;

      public TestfxmlController() {
      super("fxml/testfxml.fxml");
      }

      @Override
      public void initialize(URL url, ResourceBundle rb) {
      //works!!!!
      testChoiceBox.getItems().add("test");
      }
      }


      FXMLCode:



      <AnchorPane id="AnchorPane" prefHeight="400.0" prefWidth="600.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/11.0.1" fx:controller="TestfxmlController">
      <children>
      <ChoiceBox fx:id="testChoiceBox" layoutX="113.0" layoutY="160.0" prefWidth="150.0" />
      </children>
      </AnchorPane>


      What would I expect? I would expect Errors over errors. That the loader doesn't find the fields in the base class and that access is denied....
      But it somehow magicaly works flawless. Despite I am violating like everything possible in such a small example. I'd like to understand the "magic" behind this...







      javafx javafx-8 fxml fxmlloader openjfx






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Jan 18 at 6:51







      kai

















      asked Jan 18 at 2:56









      kaikai

      245




      245
























          1 Answer
          1






          active

          oldest

          votes


















          0














          I think I undrstand it now. The derived class is already constructed when the baseclass constructor is called - only not initialized.



          So the loader actually gets the derived class. With that given reflection is able to return the fields from the derived class.



          With that it becomes possible for the base class to initialize the fields of the derived class - even though the baseclass doesn't have any information about its future derivations. It doesn't need to. It gets that information through reflection(rsp. the loader does).



          It is not even crude as the derived class is actually known through reflection and therefore is known to be of the correct type.



          So I now think this generic FXML Popup code is actually perfectly valid.



          While this particular uscase is sound, it looks like there is a flaw in the FXML loader, when it comes to the documented usecase.



          Reason: if someone creates a control loaded from a fxml - file in the way documented(not this usecase) and distribute it as a library a user of that library may subclass it. The loader now will inject into the subclass and not in the fields it was ment to create causing a failure of the control(in this case the fields in the library class don't get initialized).



          So again: while the code in the question seems to work reliably, with this behavior the documented usecase can result in problems.






          share|improve this answer

























            Your Answer






            StackExchange.ifUsing("editor", function () {
            StackExchange.using("externalEditor", function () {
            StackExchange.using("snippets", function () {
            StackExchange.snippets.init();
            });
            });
            }, "code-snippets");

            StackExchange.ready(function() {
            var channelOptions = {
            tags: "".split(" "),
            id: "1"
            };
            initTagRenderer("".split(" "), "".split(" "), channelOptions);

            StackExchange.using("externalEditor", function() {
            // Have to fire editor after snippets, if snippets enabled
            if (StackExchange.settings.snippets.snippetsEnabled) {
            StackExchange.using("snippets", function() {
            createEditor();
            });
            }
            else {
            createEditor();
            }
            });

            function createEditor() {
            StackExchange.prepareEditor({
            heartbeatType: 'answer',
            autoActivateHeartbeat: false,
            convertImagesToLinks: true,
            noModals: true,
            showLowRepImageUploadWarning: true,
            reputationToPostImages: 10,
            bindNavPrevention: true,
            postfix: "",
            imageUploader: {
            brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
            contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
            allowUrls: true
            },
            onDemand: true,
            discardSelector: ".discard-answer"
            ,immediatelyShowMarkdownHelp:true
            });


            }
            });














            draft saved

            draft discarded


















            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54247166%2ffx-11-controller-loading-in-baseclass%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown

























            1 Answer
            1






            active

            oldest

            votes








            1 Answer
            1






            active

            oldest

            votes









            active

            oldest

            votes






            active

            oldest

            votes









            0














            I think I undrstand it now. The derived class is already constructed when the baseclass constructor is called - only not initialized.



            So the loader actually gets the derived class. With that given reflection is able to return the fields from the derived class.



            With that it becomes possible for the base class to initialize the fields of the derived class - even though the baseclass doesn't have any information about its future derivations. It doesn't need to. It gets that information through reflection(rsp. the loader does).



            It is not even crude as the derived class is actually known through reflection and therefore is known to be of the correct type.



            So I now think this generic FXML Popup code is actually perfectly valid.



            While this particular uscase is sound, it looks like there is a flaw in the FXML loader, when it comes to the documented usecase.



            Reason: if someone creates a control loaded from a fxml - file in the way documented(not this usecase) and distribute it as a library a user of that library may subclass it. The loader now will inject into the subclass and not in the fields it was ment to create causing a failure of the control(in this case the fields in the library class don't get initialized).



            So again: while the code in the question seems to work reliably, with this behavior the documented usecase can result in problems.






            share|improve this answer






























              0














              I think I undrstand it now. The derived class is already constructed when the baseclass constructor is called - only not initialized.



              So the loader actually gets the derived class. With that given reflection is able to return the fields from the derived class.



              With that it becomes possible for the base class to initialize the fields of the derived class - even though the baseclass doesn't have any information about its future derivations. It doesn't need to. It gets that information through reflection(rsp. the loader does).



              It is not even crude as the derived class is actually known through reflection and therefore is known to be of the correct type.



              So I now think this generic FXML Popup code is actually perfectly valid.



              While this particular uscase is sound, it looks like there is a flaw in the FXML loader, when it comes to the documented usecase.



              Reason: if someone creates a control loaded from a fxml - file in the way documented(not this usecase) and distribute it as a library a user of that library may subclass it. The loader now will inject into the subclass and not in the fields it was ment to create causing a failure of the control(in this case the fields in the library class don't get initialized).



              So again: while the code in the question seems to work reliably, with this behavior the documented usecase can result in problems.






              share|improve this answer




























                0












                0








                0







                I think I undrstand it now. The derived class is already constructed when the baseclass constructor is called - only not initialized.



                So the loader actually gets the derived class. With that given reflection is able to return the fields from the derived class.



                With that it becomes possible for the base class to initialize the fields of the derived class - even though the baseclass doesn't have any information about its future derivations. It doesn't need to. It gets that information through reflection(rsp. the loader does).



                It is not even crude as the derived class is actually known through reflection and therefore is known to be of the correct type.



                So I now think this generic FXML Popup code is actually perfectly valid.



                While this particular uscase is sound, it looks like there is a flaw in the FXML loader, when it comes to the documented usecase.



                Reason: if someone creates a control loaded from a fxml - file in the way documented(not this usecase) and distribute it as a library a user of that library may subclass it. The loader now will inject into the subclass and not in the fields it was ment to create causing a failure of the control(in this case the fields in the library class don't get initialized).



                So again: while the code in the question seems to work reliably, with this behavior the documented usecase can result in problems.






                share|improve this answer















                I think I undrstand it now. The derived class is already constructed when the baseclass constructor is called - only not initialized.



                So the loader actually gets the derived class. With that given reflection is able to return the fields from the derived class.



                With that it becomes possible for the base class to initialize the fields of the derived class - even though the baseclass doesn't have any information about its future derivations. It doesn't need to. It gets that information through reflection(rsp. the loader does).



                It is not even crude as the derived class is actually known through reflection and therefore is known to be of the correct type.



                So I now think this generic FXML Popup code is actually perfectly valid.



                While this particular uscase is sound, it looks like there is a flaw in the FXML loader, when it comes to the documented usecase.



                Reason: if someone creates a control loaded from a fxml - file in the way documented(not this usecase) and distribute it as a library a user of that library may subclass it. The loader now will inject into the subclass and not in the fields it was ment to create causing a failure of the control(in this case the fields in the library class don't get initialized).



                So again: while the code in the question seems to work reliably, with this behavior the documented usecase can result in problems.







                share|improve this answer














                share|improve this answer



                share|improve this answer








                edited Jan 19 at 3:03

























                answered Jan 18 at 8:13









                kaikai

                245




                245






























                    draft saved

                    draft discarded




















































                    Thanks for contributing an answer to Stack Overflow!


                    • Please be sure to answer the question. Provide details and share your research!

                    But avoid



                    • Asking for help, clarification, or responding to other answers.

                    • Making statements based on opinion; back them up with references or personal experience.


                    To learn more, see our tips on writing great answers.




                    draft saved


                    draft discarded














                    StackExchange.ready(
                    function () {
                    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54247166%2ffx-11-controller-loading-in-baseclass%23new-answer', 'question_page');
                    }
                    );

                    Post as a guest















                    Required, but never shown





















































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown

































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown







                    Popular posts from this blog

                    Liquibase includeAll doesn't find base path

                    How to use setInterval in EJS file?

                    Petrus Granier-Deferre