i have fxml controller has spring bean dependencies. can't find way autowire them in time before controller loaded, since i'm using custom fxml loader:
@bean @scope(proxymode = scopedproxymode.target_class, value = "prototype") public userprofile attachdoccontroller() throws ioexception { return (userprofile) loadcontroller("/myproject/forms/userprofile.fxml"); } fxmlloader loader = null; protected object loadcontroller(string url) throws ioexception { loader = new fxmlloader(getclass().getresource(url)); loader.load(); return loader.getcontroller(); }
using approach, can autowire beans directly injecting them via @autowired
annotation:
public class userprofile { @autowired mydependency mydependency;
this leaves me dependent on spring, , leave me code maintainability issues later on. how can autowire dependencies spring xml file configuration fxml controller class? like:
<bean id="userprofile" class="myproject.controllerinjection.userprofile" scope="prototype"> <aop:scoped-proxy proxy-target-class="true"/> <property name="mydependency" ref="mydependency" /> </bean> <bean id="mydependency" class="myproject.controllerinjection.mydependency" scope="prototype"> <aop:scoped-proxy proxy-target-class="true"/> </bean>
this seems better route, long-term project maintainability in mind, project gets larger.
update:
i'me not used lambda expressions. i've researched bit, integrating suggestion @james_d follows:
protected object loadbeancontroller(string url) throws ioexception { loader = new fxmlloader(getclass().getresource(url)); applicationcontext ctx = wakiliproject.getctx(); if (ctx != null) { system.out.println("load bean..............."); loader.setcontrollerfactory(ctx::getbean); } else { system.out.println("no app.ctx..............."); } return loader.getcontroller(); }
gives null pointer whenever try calling method of mydependency
. mydependency mydependency
never gets injected userprofile
.
when call fxmlloader.load()
, loads fxml file. if there fx:controller
attribute in root element, creates controller based on class specified (and injects fx:id
-attributed elements controller instance, etc.). loader returns root of fxml file. controller intrinsically linked fxml root.
by default, fxmlloader
maps controller class instance reflection, calling controllerclass.newinstance()
(which invokes no-arg constructor of controller class). can configure this, overriding default behavior, specifying controllerfactory
on fxmlloader
.
the controllerfactory
function maps class<?>
object (constructed class name specified in fx:controller
attribute) controller instance. if using spring manage controller instances, need function ask spring application context (bean factory) generate controller instance you. can fxmlloader.setcontrollerfactory(applicationcontext::getbean);
. setup, loading fxml file via fxmlloader
cause fxmlloader
request controller class application context. application context can configured in of ways spring allows.
so config can like
@configuration public class config { @bean @scope(proxymode = scopedproxymode.target_class, value = "prototype") public userprofile attachdoccontroller() throws ioexception { return new userprofile(); } }
of course, can inject dependencies in config class:
@bean @scope(proxymode = scopedproxymode.target_class, value = "prototype") public userprofile attachdoccontroller(mydependency mydependency) throws ioexception { return new userprofile(mydependency); } @bean public mydependency createdependency() { return new mydependencyimpl(); }
then in ui work can do
fxmlloader loader = new fxmlloader(getclass().getresource("/myproject/forms/userprofile.fxml")); loader.setcontrollerfactory(applicationcontext::getbean); parent root = loader.load(); // since can initialized in controller d.i., // shouldn't need access it, if reason can userprofile controller = loader.getcontroller();
where applicationcontext
spring application context. works whether application context use xml configuration, annotation-based configuration, or java configuration.
update
if, reason, cannot use java 8 or later, call setcontrollerfactory
java 7 compatible looks like:
loader.setcontrollerfactory(new callback<class<?>, object>() { @override public object call(class<?> c) { return applicationcontext.getbean(c); } });
you need applicationcontext
either field or final
local variable work in java 7. note @ time of writing, java 7 not publicly supported oracle.
Comments
Post a Comment