2016-03-04 7 views
5

मेरे पास जावा 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")) के साथ के साथ परिणाम को स्थानांतरित कर देगा जहां मुझे इसकी आवश्यकता है, लेकिन एक मनमानी लिपि के साथ, मुझे नहीं पता कि सभी परिवर्तनीय नाम क्या होंगे, इसलिए कोई विकल्प नहीं है।

तो प्रश्न: वैश्विक वैरिएबल के निर्माण को कैप्चर करने के लिए वैसे भी है, और मूल बाध्यकारी ऑब्जेक्ट जैसे अनुप्रयोग के नियंत्रण में जावा ऑब्जेक्ट के अंदर उन्हें स्टोर करें ??

उत्तर

3

मेरे पास एक ऐसा समाधान है जो काम करता प्रतीत होता है, लेकिन यह स्पष्ट रूप से एक हैक है।

टेस्ट कार्यक्रम:

public class Nashorn { 
    public static void main(String[] args) throws ScriptException { 
     ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn"); 

     Map<String, Object> map = new HashMap<>(); 
     map.put("a", 10); 
     map.put("b", 20); 

     try (GlobalMap globals = new GlobalMap(map)) { 
      engine.eval("c = a + b; a += b;", globals); 
     } 

     System.out.println("map = " + map); 
    } 
} 

परीक्षण कार्यक्रम आउटपुट map = {a=30.0, b=20, c=30.0} के रूप में वांछित।

GlobalMap कुंजी "nashorn.global" के तहत नैशर्न वैश्विक वस्तु के भंडारण को रोकता है, इसलिए यह मानचित्र में संग्रहीत नहीं होता है।जब GlobalMap बंद कर दिया है, यह Nashorn वैश्विक वस्तु से कोई नया वैश्विक चर दूर करता है और मूल नक्शे में उन्हें संग्रहीत करता है:

public class GlobalMap extends SimpleBindings implements Closeable { 

    private final static String NASHORN_GLOBAL = "nashorn.global"; 
    private Bindings global; 
    private Set<String> original_keys; 

    public GlobalMap(Map<String, Object> map) { 
     super(map); 
    } 

    @Override 
    public Object put(String key, Object value) { 
     if (key.equals(NASHORN_GLOBAL) && value instanceof Bindings) { 
      global = (Bindings) value; 
      original_keys = new HashSet<>(global.keySet()); 
      return null; 
     } 
     return super.put(key, value); 
    } 

    @Override 
    public Object get(Object key) { 
     return key.equals(NASHORN_GLOBAL) ? global : super.get(key); 
    } 

    @Override 
    public void close() { 
     if (global != null) { 
      Set<String> keys = new HashSet<>(global.keySet()); 
      keys.removeAll(original_keys); 
      for (String key : keys) 
       put(key, global.remove(key)); 
     } 
    } 
} 

मैं अभी भी एक समाधान जहां वर्तमान क्षेत्र एक Map<String,Object> करने के लिए सेट किया जा सकता है खोजने के लिए आशा करता हूं या Bindings ऑब्जेक्ट, और स्क्रिप्ट द्वारा बनाए गए किसी भी नए चर को सीधे उस ऑब्जेक्ट में संग्रहीत किया जाता है।

+0

यह इतना बेवकूफ है कि हमें इसका सहारा लेना है, नाशोर इंजन अपने रचनाकारों के रूप में जिद्दी है ... – grimmeld

+2

आईआईएफई के अंदर अभिव्यक्ति को आमंत्रित करना चाल भी है (आपको घोषणा के लिए 'var' कीवर्ड का उपयोग करने की आवश्यकता है चर)। किसी को पता है कि क्या उस विधि में कोई चेतावनी है? – faizan

+0

@faizan सुझाव के लिए धन्यवाद। 'Var c = ... 'के साथ IIFE का उपयोग करके' c' को वैश्विक दायरे में संग्रहीत करने से रोकता है। यह कोड को अलग करने में मदद करता है, अलग-अलग स्क्रिप्ट को अन्य स्क्रिप्ट में गणना किए गए मानों को गलती से देखने से रोकता है। लेकिन यह मूल समस्या से मदद नहीं करता है: वास्तव में प्रोग्राम के अन्य हिस्सों में उपयोग के लिए इन जावास्क्रिप्ट कोड स्निपिट को निष्पादित करने वाले जावा प्रोग्राम द्वारा प्रदान किए गए 'मानचित्र' में इन चरों में संग्रहीत गणना मूल्यों को कैप्चर करना। – AJNeufeld

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