2013-02-01 43 views
0

我想使用Weld-SE引導一個小的javafx應用程序。如果我刪除Menubar上的@Inject註釋並手動實例化,我能夠運行該應用程序。 但是,當我添加@Inject的時候,應用程序會拋出異常。下面列出的是注射點和生產者方法。這就是我所做的所有配置,我錯過了什麼?Bootstrap Javafx 2.0與焊接

注射點

@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 
+0

的重複(不幸的是,目前尚未回答)StackOverflow問題[如何在JavaFX 2應用程序中正確使用Weld?](http://stackoverflow.com/questions/10262660/how-to-properly-use-weld-in-javafx-2-application) – jewelsea

+0

但是** Matthieu Brouillard **以某種方式得到了這個工作。我能夠運行他編碼的應用程序:(我可以分享工作應用程序,如果你想看看它 http://java.dzone.com/articles/fxml-javafx-powered-cdi- jboss – ShaggyInjun

+0

@jewelsea,我想知道你是否能夠驗證我的理解,如下面的答案中所列出的。 – ShaggyInjun

回答

1

ShaggyInjun,你指的是Initializable界面,它表示你正試圖與FXMLLoader整合。以下所有信息都假定您使用FXML作爲接口定義,並僅討論將值注入FXML控制器的問題。

FXMLLoader擁有控制器工廠的概念,您應該使用它來將控制器實例與您的依賴注入系統集成。有關Oracle的Mastering FXML Tutorial中的控制器工廠的簡要討論。安迪演示definition of such a factory for Guice in his blog,並有comprehensive integration of Guice in FXML on github


對於焊接,您需要實現一個類似的控制器工廠回調機制來實現Weld提供的依賴注入功能。 Matthieu Brouillard發表的文章指出,鏈接到評論FXML & JavaFX—Fueled by CDI & JBoss Weld似乎提供了將焊接初始化和接口焊接到FXMLLoader控制器工廠機制所需的所有信息。具體而言,下面的代碼是焊接等效安迪蒂爾的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傳遞給FXMLLoader之前,將由依賴注入系統調用@PostConstruct)。


我會在這裏發佈基於安迪的吉斯的解決方案,因爲它是注射多麼相似的吉斯是完成一個小而簡單的例子(如果他的博客下線):

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); 
    } 
} 
+0

我現在看到了。我使用fxml文件來查看視圖,並且我在fxml文件中使用了硬編碼的控制器名稱(作爲調用'fxmlloader.setController'的替代方法)。我可以看到它爲什麼工作。 我在Matthieu Brouillard的博客中看到過這段代碼。我沒有使用過。目前爲止,我遵循嚴格的fxml視圖方法,所以我現在可以在視圖內對控制器名稱進行硬編碼。當我使用FXMLLoader加載視圖時,控制器由javafx自動設置。我還沒有看到需要暫停使用基於UI的javafx構建器。你的答案要詳細得多。 – ShaggyInjun

1

是因爲你正試圖在構造函數或初始化器塊使用菜單欄?

如果是這樣,請嘗試使用Initializable並在初始化中使用它們。

+0

Andy,謝謝你的回答。你的回答幫助我做了更多的研究,但我認爲還有更多的請看下面的答案。 – ShaggyInjun

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

我認爲它是安全的理解初始化的通話沒有什麼的做對象建設。相反,噹噹前節點圖的根已被完全處理時調用初始化,所以可以處理諸如事件處理程序等東西。在document.onloadjQuery(document).ready()的行上有東西。如果在對象圖準備就緒之前嘗試附加事件處理程序,那麼很有可能會看到空指針,因爲該節點不是對象圖,而且無法附加事件處理程序。

因此,在將實例加載到場景圖之前,您需要實例化對象(直接或通過注入)。因此@PostConstruct在初始化之前被調用。但是,如果直接實例化對象,那麼負責調用標註爲@PostConstruct的方法會落在你身上,否則後處理將不會發生。

結論: 假定在使用@PostConstruct註解的方法後始終調用initialize是安全的。

編輯

@Jewelsea指出,我沒有上面列出的幾個假設。所以在這裏,上述情況適用於我。

  • 將FXML文件用於視圖。
  • 在fxml文件中指定的控制器名稱。
+0

在將節點添加到場景圖之前,將事件處理程序附加到JavaFX節點沒有問題(事件處理程序只有在場景圖中才會使用,但它們不會導致任何空指針異常) 。 – jewelsea