I am trying to bootstrap a small javafx application using Weld-SE. I was able to run the application if I remove the @Inject annotation on the Menubar and instantiate it manually.
But the moment I add @Inject, the application throws exception. Listed below are the injection point and the Producer method. This is all the configuration I did, am I missing something ?
Injection Point
@Inject MenuBar menuBar
Class with producer method
public class ComponentProducer {
@Produces
public MenuBar createMenuBar(){
return new MenuBar();
}
}
Exception
491 [JavaFX Application Thread] INFO org.jboss.weld.Bootstrap - WELD-000101 Transactional services not available. Injection of @Inject UserTransaction not available. Transactional observers will be invoked synchronously.
8868 [JavaFX Application Thread] WARN org.jboss.interceptor.model.InterceptionTypeRegistry - Class 'javax.ejb.PostActivate' not found, interception based on it is not enabled
8868 [JavaFX Application Thread] WARN org.jboss.interceptor.model.InterceptionTypeRegistry - Class 'javax.ejb.PrePassivate' not found, interception based on it is not enabled
Exception in Application start method
Exception in thread "main" java.lang.RuntimeException: Exception in Application start method
at com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:399)
at com.sun.javafx.application.LauncherImpl.access$000(LauncherImpl.java:47)
at com.sun.javafx.application.LauncherImpl$1.run(LauncherImpl.java:115)
at java.lang.Thread.run(Thread.java:722)
Caused by: java.lang.NullPointerException
at net.sourceforge.squirrel_sql.client.MainScene.<init>(MainScene.java:26)
at net.sourceforge.squirrel_sql.client.FXApplication.startup(FXApplication.java:176)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at org.jboss.weld.util.reflection.SecureReflections$13.work(SecureReflections.java:304)
at org.jboss.weld.util.reflection.SecureReflectionAccess.run(SecureReflectionAccess.java:54)
at org.jboss.weld.util.reflection.SecureReflectionAccess.runAsInvocation(SecureReflectionAccess.java:163)
at org.jboss.weld.util.reflection.SecureReflections.invoke(SecureReflections.java:298)
at org.jboss.weld.introspector.jlr.WeldMethodImpl.invokeOnInstance(WeldMethodImpl.java:200)
at org.jboss.weld.introspector.ForwardingWeldMethod.invokeOnInstance(ForwardingWeldMethod.java:59)
at org.jboss.weld.injection.MethodInjectionPoint.invokeOnInstanceWithSpecialValue(MethodInjectionPoint.java:194)
at org.jboss.weld.event.ObserverMethodImpl.sendEvent(ObserverMethodImpl.java:241)
at org.jboss.weld.event.ObserverMethodImpl.notify(ObserverMethodImpl.java:216)
at org.jboss.weld.manager.BeanManagerImpl.notifyObservers(BeanManagerImpl.java:654)
at org.jboss.weld.manager.BeanManagerImpl.fireEvent(BeanManagerImpl.java:647)
at org.jboss.weld.manager.BeanManagerImpl.fireEvent(BeanManagerImpl.java:641)
at org.jboss.weld.event.EventImpl.fire(EventImpl.java:93)
at net.sourceforge.squirrel_sql.client.Main.start(Main.java:180)
at com.sun.javafx.application.LauncherImpl$5.run(LauncherImpl.java:315)
at com.sun.javafx.application.PlatformImpl$4.run(PlatformImpl.java:174)
at com.sun.javafx.application.PlatformImpl$3.run(PlatformImpl.java:141)
at com.sun.glass.ui.gtk.GtkApplication._runLoop(Native Method)
at com.sun.glass.ui.gtk.GtkApplication$2$1.run(GtkApplication.java:79)
... 1 more
ShaggyInjun, you refer to the Initializable interface which indicates you were trying to integrate with the FXMLLoader. All of the information below assumes you are using FXML for your interface definition and only discusses issues around injecting values into FXML controllers.
The
FXMLLoaderhas the concept of a controller factory, which you should use to integrate the controller instantiation with your dependency injection system. There is a brief discussion of controller factories in Oracle’s Mastering FXML Tutorial. Andy demonstrates definition of such a factory for Guice in his blog and there is a comprehensive integration of Guice in FXML on github.For Weld you will need to implement a similar controller factory callback mechanism to realize the dependency injection functionality which Weld provides. The article by Matthieu Brouillard that you linked in a comment FXML & JavaFX—Fueled by CDI & JBoss Weld would seem to provide all of the information you need to both initialize Weld and interface Weld into the FXMLLoader controller factory mechanism. Specifically, the following code is the Weld equivalent of Andy Till’s FXML based injection mechanism:
Even when an FXMLoader controller factory is used, I believe it is the FXMLLoader that is instantiating the controller. So in those cases, you should not make of annotations like
@PostConstructbecause they only apply when the dependency injection system is maintaining the lifecycle of the object – and that is not the case if the FXMLLoader creates the controller.There is one other alternative, and that it is to explicitly set the controller to be used by the FXMLLoader using setController. This would allow you to have your dependency injection system instantiate (and inject into) controllers using whatever means it wishes and then you could subsequently pass the instantiated controller to your FXMLLoader. In such cases anotations like
@PostConstructshould work as the dependency injection system is now maintaining the objects lifecycle (and@PostConstructwould be invoked by the dependency injection system after the Controller has been created and before you pass the Controller through to the FXMLLoader).I’ll post Andy’s Guice based solution here as it is a small and simple example of how similar injection is accomplished in Guice (in case his blog goes offline):