2014-04-29 7 views
6

मैं क्लोजर (1.6) और जावाएफएक्स 8 के साथ खेल रहा हूं, और शुरुआत में ही मैंने एक समस्या में भाग लिया है। उदाहरण के लिए, इस बहुत ही सरल कोड में विफल रहता है:क्लोजर स्थिर प्रारंभकर्ताओं के साथ जावाएफएक्स कक्षाओं को आयात नहीं कर सकता

(ns xxyyzz.core) 

(gen-class :name "xxyyzz.core.App" 
      :extends javafx.application.Application 
      :prefix "app-") 

(defn app-start [app stage] 
    (let [button (javafx.scene.control.Button.)])) 

(defn launch [] 
    (javafx.application.Application/launch xxyyzz.core.App (into-array String []))) 

(defn -main [] 
    (launch)) 

यह स्टैक ट्रेस के अंतिम भाग है कि प्रासंगिक लगता है:

Caused by: java.lang.ExceptionInInitializerError 
     at java.lang.Class.forName0(Native Method) 
     at java.lang.Class.forName(Class.java:340) 
     at clojure.lang.RT.classForName(RT.java:2070) 
     at clojure.lang.Compiler$HostExpr.maybeClass(Compiler.java:969) 
     at clojure.lang.Compiler$HostExpr.access$400(Compiler.java:747) 
     at clojure.lang.Compiler$NewExpr$Parser.parse(Compiler.java:2494) 
     at clojure.lang.Compiler.analyzeSeq(Compiler.java:6560) 
     ... 48 more 
Caused by: java.lang.IllegalStateException: Toolkit not initialized 
     at com.sun.javafx.application.PlatformImpl.runLater(PlatformImpl.java:276) 
     at com.sun.javafx.application.PlatformImpl.runLater(PlatformImpl.java:271) 
     at com.sun.javafx.application.PlatformImpl.setPlatformUserAgentStylesheet(PlatformImpl.java:562) 
     at com.sun.javafx.application.PlatformImpl.setDefaultPlatformUserAgentStylesheet(PlatformImpl.java:524) 
     at javafx.scene.control.Control.<clinit>(Control.java:81) 
     ... 55 more 

मैं जावा में बात नहीं करते, लेकिन इस शोध ऐसा लगता है कि समस्या क्लोजर के साथ निहित है और जिस तरह से यह जावा कक्षाओं का आयात करता है। अगर मैं सही ढंग से समझता हूं, आयात समय पर यह क्लास स्थैतिक प्रारंभकर्ता चलाता है, और कुछ जावाएफएक्स कक्षाओं (Button मेरे मामले में) जो दुर्घटनाग्रस्त हो जाता है।

मान लीजिए मेरे पास दो प्रश्न हैं: क्या इस त्रुटि की मेरी समझ सही है? और दूसरा, क्या इस समस्या के आसपास किसी भी तरह काम करने का कोई तरीका है? मैंने (एनएस) घोषणा के बजाय कार्यों के अंदर आयात खींचने की कोशिश की है, लेकिन यह अभी भी काम नहीं करता है।

यदि कोई क्लोजर फ़िक्स नहीं है, तो क्या यह संभवतः कुछ अतिरिक्त जावा कोड के साथ तय किया जा सकता है?

कोई सुझाव और पॉइंटर्स का स्वागत है!

उत्तर

3

मुझे क्लोजर के आयात व्यवहार को बदलने का कोई तरीका नहीं मिला, लेकिन मुझे जो कुछ चाहिए उसे करने के लिए मुझे कुछ हैक्स मिल गए।

सबसे पहले, जावाएफएक्स बिल्डर वर्ग प्रदान करता है, इसलिए इस विशेष मामले में सबसे साफ तरीका नए बटन बनाने के लिए ButtonBuilder का उपयोग करना होगा।

दूसरा तरीका एक साधारण जावा क्लास लिखना होगा जो Button को लपेटता है, और उसके बाद क्लोजर के पक्ष आयात से लपेटता है। समस्याग्रस्त वर्गों की छोटी संख्या के साथ काम करते समय यह एक अच्छा समाधान है।

तीसरा रास्ता (इस के साथ बाहर की मदद करने के लिए #clojure पर लोगों के लिए धन्यवाद) कार्यावधि में आयात करने के लिए, कुछ इस तरह होगा:

(defn import-at-runtime [name] 
    (.importClass (the-ns *ns*) 
       (clojure.lang.RT/classForName name))) 

(import-at-runtime "javafx.scene.control.Button") 

(let [button (eval `(new ~(symbol "javafx.scene.control.Button") ~"Button Text")) 

अंत में, इस Clojure के जावा में एक बदसूरत मस्सा की तरह लगता है इंटरऑप, अगर यह भविष्य में तय किया जा सकता है तो यह बहुत अच्छा होगा।


अद्यतन: वहाँ भी है clojure.lang.RT/classForNameNonLoading, लेकिन दुर्भाग्य से, यह Clojure 1.6 के रूप में public नहीं है। यह Clojure में इसे फिर से लागू करने के लिए आसान है, हालांकि:

(fn [^String class-name] 
    (Class/forName class-name false (clojure.lang.RT/baseLoader))) 

बाद में, वर्ग clojure.lang.Reflector/invokeConstructor साथ instantiated जा सकता है।

संबंधित मुद्दे