मेरे पास जावा 7 प्रोग्राम है, जो हजारों ऑब्जेक्ट्स (घटकों) को लोड करता है, प्रत्येक पैरामीटर (Map
में संग्रहीत) के साथ, और उन ऑब्जेक्ट्स पर विभिन्न राइनो स्क्रिप्ट निष्पादित करता है जो अन्य व्युत्पन्न पैरामीटर की गणना करने के लिए संग्रहीत करते हैं ऑब्जेक्ट के Map
में वापस। प्रत्येक स्क्रिप्ट चलाने से पहले, Scope
ऑब्जेक्ट को ऑब्जेक्ट के मानचित्र द्वारा समर्थित किया जाता है, जिसे स्क्रिप्ट की अवधि के लिए जावास्क्रिप्ट के दायरे के रूप में उपयोग किया जाता है।नैशर्न के ग्लोबल वेरिएबल्स को कैप्चर करना
एक साधारण उदाहरण के रूप में, निम्नलिखित एक = 10 और ख = 20 के साथ एक HashMap
बनाता है, और स्क्रिप्ट c = a + b
, जो c = 30.0
मानचित्र में वापस जमा हो जाती परिणाम निष्पादित करता है। हालांकि स्क्रिप्ट ऐसा लगता है कि यह वैश्विक चर c
बना रहा है, Scope
ऑब्जेक्ट इसे कैप्चर करता है और इसे मानचित्र में संग्रहीत करता है;
public class Rhino {
public static void main(String[] args) throws ScriptException {
Context cx = Context.enter();
Scriptable root_scope = cx.initStandardObjects();
Map<String, Object> map = new HashMap<>();
map.put("a", 10);
map.put("b", 20);
Scope scope = new Scope(root_scope, map);
cx.evaluateString(scope, "c = a + b", "<expr>", 0, null);
System.out.println(map); // --> {b=20, c=30.0, a=10}
Context.exit();
}
static class Scope extends ScriptableObject {
private Map<String, Object> map;
public Scope(Scriptable parent, Map<String, Object> map) {
setParentScope(parent);
this.map = map;
}
@Override
public boolean has(String key, Scriptable start) {
return true;
}
@Override
public Object get(String key, Scriptable start) {
if (map.containsKey(key))
return map.get(key);
return Scriptable.NOT_FOUND;
}
@Override
public void put(String key, Scriptable start, Object value) {
map.put(key, value);
}
@Override
public String getClassName() {
return "MapScope";
}
}
}
ऊपर स्क्रिप्ट आउटपुट {b=20, c=30.0, a=10}
, चर c
दिखा Map
में संग्रहीत कर दिया गया है एक और स्क्रिप्ट एक अलग Scope
वस्तु के साथ मार डाला इस चर नहीं देख सकेंगे।
अब, मुझे जावा 8 माइग्रेट करने और नैशर्न का उपयोग करने की आवश्यकता है। हालांकि, मुझे लगता है कि नैशर्न हमेशा एक विशेष "nashorn.global"
ऑब्जेक्ट में वैश्विक चर स्टोर करता है। वास्तव में, ऐसा लगता है कि यह सभी बाइंडिंग को केवल पढ़ने के लिए ही व्यवहार कर रहा है, और मौजूदा वैरिएबल को बदलने के प्रयासों के परिणामस्वरूप मौजूदा बाध्यकारी को एक नए वैश्विक चर में बदल दिया गया है।
public class Nashorn {
private final static ScriptEngineManager MANAGER = new ScriptEngineManager();
public static void main(String[] args) throws ScriptException {
new Nashorn().testBindingsAsArgument();
new Nashorn().testScopeBindings("ENGINE_SCOPE", ScriptContext.ENGINE_SCOPE);
new Nashorn().testScopeBindings("GLOBAL_SCOPE", ScriptContext.GLOBAL_SCOPE);
}
private ScriptEngine engine = MANAGER.getEngineByName("nashorn");
private Map<String, Object> map = new HashMap<>();
private Bindings bindings = new SimpleBindings(map);
private Nashorn() {
map.put("a", 10);
map.put("b", 20);
}
private void testBindingsAsArgument() throws ScriptException {
System.out.println("Bindings as argument:");
engine.eval("c = a + b; a += b", bindings);
System.out.println("map = " + map);
System.out.println("eval('c', bindings) = " + engine.eval("c", bindings));
System.out.println("eval('a', bindings) = " + engine.eval("a", bindings));
}
private void testScopeBindings(String scope_name, int scope) throws ScriptException {
System.out.println("\n" + scope_name + ":");
engine.getContext().setBindings(bindings, scope);
engine.eval("c = a + b; a += b");
System.out.println("map = " + map);
System.out.println("eval('c') = " + engine.eval("c"));
System.out.println("eval('a') = " + engine.eval("a"));
}
}
आउटपुट:
Bindings as argument:
map = {a=10, b=20, nashorn.global=[object global]}
eval('c', bindings) = 30.0
eval('a', bindings) = 30.0
ENGINE_SCOPE:
map = {a=10, b=20, nashorn.global=[object global]}
eval('c') = 30.0
eval('a') = 30.0
GLOBAL_SCOPE:
map = {a=10, b=20}
eval('c') = 30.0
eval('a') = 30.0
eval
उत्पादन लाइनों दिखाने के परिणाम सही ढंग से गणना और संग्रहीत किया जा रहा हैं, लेकिन map
उत्पादन लाइनों से पता चलता परिणाम संग्रहीत नहीं किया जा रहा है, जहां मैं उन्हें इच्छा हो।
यह कई कारणों से स्वीकार्य नहीं है। व्यक्तिगत वस्तुओं को अपने स्थानीय भंडारण में वापस संग्रहीत गणना पैरामीटर नहीं मिलते हैं। अन्य ऑब्जेक्ट्स पर निष्पादित अन्य स्क्रिप्ट से वेरिएबल पिछले स्क्रिप्ट निष्पादन से आगे बढ़ेंगे, जो तर्क त्रुटियों को छुपा सकता है (एक स्क्रिप्ट गलती से एक अपरिभाषित चर नाम का उपयोग कर सकती है, लेकिन यदि यह नाम वास्तव में पिछली लिपि द्वारा उपयोग किया गया था, तो पुराना कचरा मूल्य ReferenceError
उत्पन्न होने के बजाय, त्रुटि छिपाने के बजाय उपयोग किया जाना चाहिए)।
map.put("c", engine.get("c"))
के साथ के साथ परिणाम को स्थानांतरित कर देगा जहां मुझे इसकी आवश्यकता है, लेकिन एक मनमानी लिपि के साथ, मुझे नहीं पता कि सभी परिवर्तनीय नाम क्या होंगे, इसलिए कोई विकल्प नहीं है।
तो प्रश्न: वैश्विक वैरिएबल के निर्माण को कैप्चर करने के लिए वैसे भी है, और मूल बाध्यकारी ऑब्जेक्ट जैसे अनुप्रयोग के नियंत्रण में जावा ऑब्जेक्ट के अंदर उन्हें स्टोर करें ??
यह इतना बेवकूफ है कि हमें इसका सहारा लेना है, नाशोर इंजन अपने रचनाकारों के रूप में जिद्दी है ... – grimmeld
आईआईएफई के अंदर अभिव्यक्ति को आमंत्रित करना चाल भी है (आपको घोषणा के लिए 'var' कीवर्ड का उपयोग करने की आवश्यकता है चर)। किसी को पता है कि क्या उस विधि में कोई चेतावनी है? – faizan
@faizan सुझाव के लिए धन्यवाद। 'Var c = ... 'के साथ IIFE का उपयोग करके' c' को वैश्विक दायरे में संग्रहीत करने से रोकता है। यह कोड को अलग करने में मदद करता है, अलग-अलग स्क्रिप्ट को अन्य स्क्रिप्ट में गणना किए गए मानों को गलती से देखने से रोकता है। लेकिन यह मूल समस्या से मदद नहीं करता है: वास्तव में प्रोग्राम के अन्य हिस्सों में उपयोग के लिए इन जावास्क्रिप्ट कोड स्निपिट को निष्पादित करने वाले जावा प्रोग्राम द्वारा प्रदान किए गए 'मानचित्र' में इन चरों में संग्रहीत गणना मूल्यों को कैप्चर करना। – AJNeufeld