带Weld的Bootstrap Javafx 2.0

时间:2013-02-01 20:40:52

标签: javafx-2 weld

我正在尝试使用Weld-SE引导一个小型的javafx应用程序。如果我删除@Inject上的Menubar注释并手动实例化,我就可以运行该应用程序。 但是当我添加@Inject时,应用程序抛出异常。下面列出了注入点和生产者方法。这就是我所做的所有配置,我错过了什么?

注射点

@Inject MenuBar menuBar

使用生产者方法的类

public class ComponentProducer {

    @Produces
    public MenuBar createMenuBar(){
        return new MenuBar();
    }

}

异常

    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

3 个答案:

答案 0 :(得分:1)

是因为你试图在构造函数或初始化块中使用menuBar吗?

如果是这样,请尝试使用Initializable并在初始化时使用它们。

答案 1 :(得分:1)

ShaggyInjun,您可以参考Initializable界面,该界面表明您尝试与FXMLLoader集成。以下所有信息均假定您使用FXML作为接口定义,并仅讨论将值注入FXML控制器的问题。

FXMLLoader具有控制器工厂的概念,您应该使用它来将控制器实例与您的依赖注入系统集成。在Oracle Mastering FXML Tutorial中对控制器工厂进行了简要讨论。 Andy演示definition of such a factory for Guice in his blog并且有comprehensive integration of Guice in FXML on github


对于Weld,您需要实现类似的控制器工厂回调机制,以实现Weld提供的依赖注入功能。 Matthieu Brouillard在评论FXML & JavaFX—Fueled by CDI & JBoss Weld中链接的文章似乎提供了初始化Weld和将Weld接口到FXMLLoader控制器工厂机制所需的所有信息。具体来说,下面的代码是Weld等同于Andy Till的基于FXML的注入机制:

public class FXMLLoaderProducer {
  @Inject Instance<Object> instance;
  @Produces public FXMLLoader createLoader() {
    FXMLLoader loader = new FXMLLoader();
    loader.setControllerFactory(new Callback<Class<?>, Object>() {
      @Override public Object call(Class<?> param) {
        return instance.select(param).get();
      }
    });
    return loader;
  }
}

即使使用FXMLoader控制器工厂,我相信它是实例化控制器的FXMLLoader。因此,在这些情况下,您不应该使用@PostConstruct之类的注释,因为它们仅在依赖注入系统维护对象的生命周期时才适用 - 如果FXMLLoader创建控制器则不是这样。

还有另外一种选择,它是使用setController显式设置FXMLLoader使用的控制器。这将允许您让依赖注入系统使用它希望的任何方式实例化(并注入)控制器,然后您可以随后将实例化的控制器传递给您的FXMLLoader。在这种情况下,像@PostConstruct这样的语言应该起作用,因为依赖注入系统现在正在维护对象生命周期(并且在创建Controller之后和传递Controller之前,依赖注入系统将调用@PostConstruct通过FXMLLoader)。


我会在这里发布Andy的基于Guice的解决方案,因为它是Guice中完成类似注入的一个小而简单的例子(如果他的博客脱机):

class GuiceControllerFactory implements Callback<Class<?>, Object> {
  private final Injector injector;
  public GuiceControllerFactory(Injector anInjector) {
    injector = anInjector;
  }     
  @Override public Object call(Class<?> aClass) {
    return injector.getInstance(aClass);
  }
}

答案 2 :(得分:0)

EJB文档声明在注入完成后将调用使用@PostConstruct注释的方法,并且这是期望可变注入的方法。

@PostConstruct

The PostConstruct annotation is used on a method that needs to be executed after dependency injection is done to perform any initialization.

期望在initialize内初始化变量似乎确实有效。

根据Initializable文档,初始化为Called to initialize a controller after its root element has been completely processed. Initializable

初始化和@PostConstruct的调用顺序

我认为可以安全地理解,初始化的调用与对象构造没有任何关系。相反,当完全处理当前节点图的根时调用initialize,因此可以处理诸如事件处理程序等的事情。document.onloadjQuery(document).ready()的行。如果您在对象图准备好之前尝试附加事件处理程序,则很有可能看到空指针,因为该节点不是对象图,但却无法附加事件处理程序。

因此,在将对象加载到场景图之前,您将实例化一个对象(直接或通过注入)。因此在初始化之前调用@PostConstruct。但是,如果直接实例化对象,则调用注释@PostConstruct的方法的责任落在你身上,否则后处理将不会发生。

结论: 可以安全地假设在使用@PostConstruct注释的方法之后始终调用initialize。

修改

@Jewelsea指出了一些我未在上面列出的假设。所以在这里,上述情况对我有用。

  • 将FXML文件用于视图。
  • fxml文件中指定的控制器名称。