Search code examples
javanashorn

How to get a configured attribute in Nashorn called method


I need to configure some attribute in ScriptEngine- or ScriptContext-level, to be used in Java methods.

So, how to get a reference to that ScriptContext in order to retrieve the value?

Example: setting the attribute:

public static void main(String[] args) throws Exception {
    ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");
    engine.getContext().setAttribute("param1", "paramValue", ScriptContext.ENGINE_SCOPE);

    engine.put("MyWindow", engine.eval("Java.type(\"" + MyWindow.class.getName() + "\")"));
    engine.eval("print(new MyWindow().test());");
}

MyWindow implementation: how to get that attribute?

public class MyWindow {

    public String test() {
        // how to get 'param1' value here
        return "in test";
    }
}

Solution

  • Pass it in:

    engine.eval("print(new MyWindow().test(param1));");
    //                                     ^^^^^^
    
    //                 vvvvvvvvvvvvv
    public String test(String param1) {
        // how to get 'param1' value here
        return "in test";
    }
    

    Update

    If you have code with a call stack like javaMethod1 -> JavaScript -> javaMethod2, and you want a value from javaMethod1 to be available to javaMethod2, without changing the JavaScript to pass it on, use a ThreadLocal.

    Since your code is in main you could just use a static directly, but I'm assuming your context is more complex. The code below works even in multi-threaded contexts. The ThreadLocal can be stored anywhere, it just has to be static and available to both java methods.

    public static void main(String[] args) throws Exception {
        MyWindow.param1.set("paramValue");
        try {
            ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");
            engine.eval("var MyWindow = Java.type(\"" + MyWindow.class.getName() + "\");" +
                        "print(new MyWindow().test());");
        } finally {
            MyWindow.param1.remove();
        }
    }
    
    public class MyWindow {
        public static final ThreadLocal<String> param1 = new ThreadLocal<>();
        public String test() {
            String value = param1.get();
            return "in test: param1 = " + value;
        }
    }