FX 11: Controller loading in Baseclass
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
add a comment |
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
add a comment |
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
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
javafx javafx-8 fxml fxmlloader openjfx
edited Jan 18 at 6:51
kai
asked Jan 18 at 2:56
kaikai
245
245
add a comment |
add a comment |
1 Answer
1
active
oldest
votes
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.
add a comment |
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
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
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.
add a comment |
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.
add a comment |
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.
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.
edited Jan 19 at 3:03
answered Jan 18 at 8:13
kaikai
245
245
add a comment |
add a comment |
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.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
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