I've got a javafx
controller that looks like this
public class DictionaryFxController implements Initializable {
@Inject
private QueryTemplate queryTemplate;
@SuppressWarnings("unchecked")
@Override
public void initialize(URL location, ResourceBundle resources) {
....
queryTemplate.insert(langs);
....
}
}
My application
class looks like this
public class Main extends Application {
public static void main(String[] args) throws Exception {
launch(args);
}
@Override
public void start(Stage primaryStage) throws Exception {
Injector injector = Guice.createInjector(new ApplicationModule());
Scene scene = null;
FXMLLoader loader = new FXMLLoader();
try {
Parent root = loader.load(getClass().getResourceAsStream("/dictionary.fxml"));
loader.setControllerFactory(injector::getInstance);
scene = new Scene(root);
} catch (IOException e) {
throw new IllegalStateException(e);
}
primaryStage.setTitle("Dictionary");
primaryStage.setScene(scene);
primaryStage.show();
}
}
My class that provides Hibernate
session looks like this
@Singleton
public class HibernateController {
private SessionFactory sessionFactory;
public HibernateController() {
sessionFactory = new Configuration()
.configure()
.buildSessionFactory();
}
public Session openSession() {
return sessionFactory.openSession();
}
@PreDestroy
private void close() {
sessionFactory.close();
StandardServiceRegistryBuilder.destroy(sessionFactory.getSessionFactoryOptions().getServiceRegistry());
}
}
I wire this class into template
that I use to peform queries
public class QueryTemplate {
private HibernateController hibernateController;
@Inject
public QueryTemplate(HibernateController controller) {
this.hibernateController = controller;
}
public <T> void insert(List<T> objects) {
try (Session session = hibernateController.openSession()) {
Transaction tx = session.beginTransaction();
// generalize
objects.forEach(session::save);
tx.commit();
}
}
}
I bound this class in the module
public class ApplicationModule extends AbstractModule {
@Override
protected void configure() {
bind(QueryTemplate.class);
}
}
But when I start the application, it fails on the line
queryTemplate.insert(langs);
because queryTemplate
is null.
What is the problem?
You are setting the controller factory after loading the FXML; the controller will already have been created at that point. Since the FXMLLoader
will use the default mechanism for creating the controller - i.e. simply calling the controller's default constructor - the controller is not managed by Guice and won't have its injected fields initialized.
You can fix the problem simply by reversing the order of the lines with loader.setControllerFactory(...)
and loader.load(...)
.
As an aside, it is better to set the location of an FXMLLoader
than to use the load(InputStream)
method. If you use the method taking a Stream
, the location is not set, and location resolution will not work properly in your FXML file.
So replace
FXMLLoader loader = new FXMLLoader();
try {
Parent root = loader.load(getClass().getResourceAsStream("/dictionary.fxml"));
loader.setControllerFactory(injector::getInstance);
scene = new Scene(root);
} catch (IOException e) {
throw new IllegalStateException(e);
}
with
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("/dictionary.fxml"));
loader.setControllerFactory(injector::getInstance);
try {
Parent root = loader.load();
scene = new Scene(root);
} catch (IOException e) {
throw new IllegalStateException(e);
}
You can combine the first two lines into the single line
FXMLLoader loader = new FXMLLoader(getClass().getResource("/dictionary.fxml"));
if you prefer.