java - How to autowire Spring beans into a FXML controller class via a Spring XML config file -


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