2010-08-09 18 views
8

मैं मोज़िला राइनो जावास्क्रिप्ट एमुलेटर का उपयोग कर रहा हूं। यह मुझे संदर्भ में जावा विधियों को जोड़ने की अनुमति देता है और फिर उन्हें कॉल करता है जैसे कि वे जावास्क्रिप्ट फ़ंक्शन थे। लेकिन जब मैं एक स्थिर विधि का उपयोग करता हूं, तो मैं इसे काम पर नहीं ला सकता हूं।मैं जावास्क्रिप्ट से जावा इंस्टेंस की विधि कैसे कॉल करूं?

विधि स्थिर नहीं है, तो जावा 'इस' मूल्य जावास्क्रिप्ट 'इस' मूल्य के अनुरूप होगा:

समस्या प्रलेखन के इस भाग है। फ़ंक्शन को 'इस' मान के साथ कॉल करने का कोई भी प्रयास जो कि सही जावा प्रकार का नहीं है, परिणामस्वरूप एक त्रुटि होगी।

जाहिर है, मेरा जावा "यह" मान जावास्क्रिप्ट में किसी के साथ मेल नहीं खाता है और मुझे नहीं पता कि उन्हें कैसे मेल करना है। अंत में, मैं जावा में एक उदाहरण बनाना चाहता हूं, और वैश्विक दायरे में इसके कुछ तरीकों को स्थापित करना चाहता हूं, इसलिए मैं जावा से इंस्टेंस प्रारंभ कर सकता हूं लेकिन इसे अपनी स्क्रिप्ट में उपयोग कर सकता हूं।

क्या किसी के पास इसके लिए कुछ उदाहरण कोड है?

उत्तर

8

एक जावा विधि (स्थिर या गैर स्थिर है या नहीं) है करने के लिए एक गुंजाइश हम निम्न तर्क का उपयोग भीतर एक वैश्विक समारोह के रूप में उपलब्ध कराया जाना है:

FunctionObject javascriptFunction = new FunctionObject(/* String*/ javascriptFunctionName, /* Method */ javaMethod, /*Scriptable */ parentScope); 
boundScope.put(javascriptFunctionName, boundScope, javascriptFunction); 

यहाँ boundScope हमेशा में गुंजाइश होनी चाहिए जो समारोह उपलब्ध कराया जाना है।

हालांकि माता-पिता के दायरे का मूल्य इस बात पर निर्भर करता है कि हम एक उदाहरण विधि या स्थैतिक विधि को बाध्य कर रहे हैं या नहीं। एक स्थैतिक विधि के मामले में, यह कोई भी क्षेत्र हो सकता है जो समझ में आता है। यह boundScope जैसा भी हो सकता है।

लेकिन उदाहरण विधि के मामले में, parentScope वह उदाहरण होना चाहिए जिसकी विधि बाध्य हो रही है।

उपर्युक्त पृष्ठभूमि जानकारी थी। अब मैं समझाऊंगा कि समस्या क्या है और इसके लिए एक प्राकृतिक समाधान दें यानी एक ऐसा जो कि वस्तु के उदाहरण को स्पष्ट रूप से बनाने और फिर उस उदाहरण का उपयोग करके विधि का आह्वान करने के बजाय इंस्टेंस विधि को वैश्विक कार्य के रूप में सीधे आमंत्रित करने की अनुमति देता है।

जब कोई फ़ंक्शन कहा जाता है, तो राइनो FunctionObject.call() विधि को आमंत्रित करता है जिसे this का संदर्भ पारित किया जाता है।यदि फ़ंक्शन एक वैश्विक फ़ंक्शन है, तो इसे this (यानी xxx()this.xxx() के बजाय) के संदर्भ के बिना कहा जाता है, this वैरिएबल का मान FunctionObject.call() विधि को पारित किया जाता है वह तरीका है जिसमें कॉल किया गया था (यानी इस मामले में this पैरामीटर का मान scope पैरामीटर के मान के समान होगा)।

तो विधि स्थिर नहीं है, जावा this मूल्य जावास्क्रिप्ट के अनुरूप होगा:

इस मामले में जावा विधि लागू किया जा रहा में एक समस्या बन जाता है क्योंकि FunctionObject वर्ग के निर्माता की Javadocs के अनुसार एक उदाहरण विधि है this मूल्य। this मान के साथ फ़ंक्शन को कॉल करने का कोई भी प्रयास सही जावा प्रकार का नहीं है जिसके परिणामस्वरूप त्रुटि हो जाएगी।

और ऊपर वर्णित परिदृश्य में यह बिल्कुल मामला है। जावास्क्रिप्ट this मान जावा this मान के अनुरूप नहीं है और परिणामस्वरूप एक असंगत वस्तु त्रुटि होती है।

समाधान FunctionObject उपवर्ग के लिए, call() विधि ओवरराइड, जबरदस्ती 'फिक्स' this संदर्भ, और फिर कॉल सामान्य रूप से आगे बढ़ना जाने है।

तो कुछ की तरह:

FunctionObject javascriptFunction = new MyFunctionObject(javascriptFunctionName, javaMethod, parentScope); 
boundScope.put(javascriptFunctionName, boundScope, javascriptFunction); 


private static class MyFunctionObject extends FunctionObject { 

    private MyFunctionObject(String name, Member methodOrConstructor, Scriptable parentScope) { 
     super(name, methodOrConstructor, parentScope); 
    } 

    @Override 
    public Object call(Context cx, Scriptable scope, Scriptable thisObj, Object[] args) { 
     return super.call(cx, scope, getParentScope(), args); 
    } 
    } 

मैं यह सबसे अच्छा एक आत्म निहित/पूर्ण उदाहरण नीचे चिपकाया गया समझी जाती हो लगता है। इस उदाहरण में, हम आवृत्ति विधि का खुलासा कर रहे हैं: myJavaInstanceMethod (डबल नंबर) एक जावास्क्रिप्ट स्कोप ('scriptExecutionScope') के भीतर वैश्विक फ़ंक्शन के रूप में। तो इस मामले में 'parentScope' पैरामीटर का मान उस विधि का उदाहरण होना चाहिए जिसमें इस विधि (यानी MyScriptable) शामिल है।

package test; 

import org.mozilla.javascript.*; 

import java.lang.reflect.Member; 
import java.lang.reflect.Method; 

//-- This is the class whose instance method will be made available in a JavaScript scope as a global function. 
//-- It extends from ScriptableObject because instance methods of only scriptable objects can be directly exposed 
//-- in a js scope as a global function. 
public class MyScriptable extends ScriptableObject { 

    public static void main(String args[]) throws Exception { 

    Context.enter(); 
    try { 
     //-- Create a top-level scope in which we will execute a simple test script to test if things are working or not. 
     Scriptable scriptExecutionScope = new ImporterTopLevel(Context.getCurrentContext()); 
     //-- Create an instance of the class whose instance method is to be made available in javascript as a global function. 
     Scriptable myScriptable = new MyScriptable(); 
     //-- This is not strictly required but it is a good practice to set the parent of all scriptable objects 
     //-- except in case of a top-level scriptable. 
     myScriptable.setParentScope(scriptExecutionScope); 

     //-- Get a reference to the instance method this is to be made available in javascript as a global function. 
     Method scriptableInstanceMethod = MyScriptable.class.getMethod("myJavaInstanceMethod", new Class[]{Double.class}); 
     //-- Choose a name to be used for invoking the above instance method from within javascript. 
     String javascriptFunctionName = "myJavascriptGlobalFunction"; 
     //-- Create the FunctionObject that binds the above function name to the instance method. 
     FunctionObject scriptableInstanceMethodBoundJavascriptFunction = new MyFunctionObject(javascriptFunctionName, 
       scriptableInstanceMethod, myScriptable); 
     //-- Make it accessible within the scriptExecutionScope. 
     scriptExecutionScope.put(javascriptFunctionName, scriptExecutionScope, 
       scriptableInstanceMethodBoundJavascriptFunction); 

     //-- Define a simple test script to test if things are working or not. 
     String testScript = "function simpleJavascriptFunction() {" + 
       " try {" + 
       " result = myJavascriptGlobalFunction(12.34);" + 
       " java.lang.System.out.println(result);" + 
       " }" + 
       " catch(e) {" + 
       " throw e;" + 
       " }" + 
       "}" + 
       "simpleJavascriptFunction();"; 

     //-- Compile the test script. 
     Script compiledScript = Context.getCurrentContext().compileString(testScript, "My Test Script", 1, null); 
     //-- Execute the test script. 
     compiledScript.exec(Context.getCurrentContext(), scriptExecutionScope); 
    } catch (Exception e) { 
     throw e; 
    } finally { 
     Context.exit(); 
    } 
    } 

    public Double myJavaInstanceMethod(Double number) { 
    return number * 2.0d; 
    } 

    @Override 
    public String getClassName() { 
    return getClass().getName(); 
    } 

    private static class MyFunctionObject extends FunctionObject { 

    private MyFunctionObject(String name, Member methodOrConstructor, Scriptable parentScope) { 
     super(name, methodOrConstructor, parentScope); 
    } 

    @Override 
    public Object call(Context cx, Scriptable scope, Scriptable thisObj, Object[] args) { 
     return super.call(cx, scope, getParentScope(), args); 
//  return super.call(cx, scope, thisObj, args); 
    } 
    } 
} 

आप ठीक से व्यवहार को देखने के लिए चाहते हैं तो टिप्पणी हटाएं लाइन 78 और टिप्पणी लाइन 79:

return super.call(cx, scope, getParentScope(), args); 
//return super.call(cx, scope, thisObj, args); 

आप ठीक बिना व्यवहार को देखने के लिए चाहते हैं तो टिप्पणी लाइन 78 और टिप्पणी हटाएं लाइन 79:

//return super.call(cx, scope, getParentScope(), args); 
return super.call(cx, scope, thisObj, args); 

उम्मीद है कि इससे मदद मिलती है।

+0

जावा आवृत्ति से मैं उपयोग करने योग्य 'पैरेंटस्कोप' कैसे प्राप्त करूं? –

+0

मैंने एक पूर्ण उदाहरण के साथ उत्तर अद्यतन किया है। उम्मीद है की वो मदद करदे। – Jawad

+0

धन्यवाद। –

3

जावास्क्रिप्ट संदर्भ में जावा उदाहरण को बाध्य करने के लिए आप क्या कर सकते हैं, और उसके बाद जावास्क्रिप्ट से पहचानकर्ता "वास्तविक" जावा ऑब्जेक्ट का संदर्भ होगा। इसके बाद आप जावास्क्रिप्ट से जावा तक विधि कॉल करने के लिए इसका उपयोग कर सकते हैं।

जावा पक्ष:

final Bindings bindings = engine.createBindings(); 
    bindings.put("javaObject", new YourJavaClass()); 
    engine.setBindings(bindings, ScriptContext.ENGINE_SCOPE); 

जावास्क्रिप्ट:

javaObject.methodName("something", "something"); 

अब जब कि उदाहरण मानता है आप जावा और राइनो के बीच पाने के लिए JDK 6 java.util.script एपीआई का उपयोग कर रहे। "सादे" राइनो से, यह थोड़ा अलग है लेकिन बुनियादी विचार वही है।

वैकल्पिक रूप से, आप जावा क्लास को जावास्क्रिप्ट वातावरण में आयात कर सकते हैं, और जब आप जावा कक्षाओं के संदर्भों पर जावास्क्रिप्ट "नया" का उपयोग करते हैं तो राइनो आपको जावा ऑब्जेक्ट्स के लिए जावास्क्रिप्ट-डोमेन संदर्भ देता है।

+0

धन्यवाद, यह काम करता है। चूंकि मैं सीधे राइनो एपीआई का उपयोग करता हूं, कोड है: 'global.defineProperty (" javaObject ", javaObject, ScriptableObject.CONST); '(हालांकि मुझे' CONST' के बारे में निश्चित नहीं है - लेकिन अन्य विशेषताएँ भी कम लागू होती हैं) । –

+0

यदि मैं [[1,3], [4,5], [6,9]] जैसे बहुआयामी पूर्णांक सरणी का उपयोग करके फ़ंक्शन को कॉल करना चाहता हूं तो फिर मैं ऑब्जेक्ट [] को पैराम्स के रूप में कैसे पास कर सकता हूं? –

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

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