Search code examples
javascriptjavanashorn

using Javascript to set Java fields


Setting variables directly in Java classes doesn't seem to be working. Why not? What is the proper syntax? Where does the variable go??

The following prints out 2 and 1. Thus the f.x=2; never happened according to the object f of Foo.

@Test
    public void testJS2Java() throws IOException, ScriptException, Exception {
        ScriptEngineManager factory = new ScriptEngineManager();// create JavaScript engine
        ScriptEngine engine = factory.getEngineByName("JavaScript");
        class Foo {
            int x = 1;
        }
        Foo f = new Foo();
        engine.put("f", f);
        System.out.println(engine.eval("f.x=2;"));
        System.out.println(f.x);
    }

The f.x=2; executes without error but which x was set?


Solution

  • Three issues with your test:

    1. Nashorn allows access only to public members of public classes (from exported modules for jdk9+) only. The local class Foo is not public. So its members are not accessible from JavaScript.
    2. Nashorn allows access to static members only from "Java type objects" and not from instances of Java types. (different from Java).
    3. Nashorn would ignore property sets on Java object if no public field or public bean property with appropriate setter is found.

    A working sample demonstrating access to a static Java field from Nashorn:

    import javax.script.*;
    
    public class Main {
        public static int x = 10;
        public static void main(String[] args) throws Exception {
            ScriptEngine e = new ScriptEngineManager().
                getEngineByName("JavaScript");
    
            // access type object for Java class "Main" using Java.type
            e.eval("var M = Java.type('Main');");
    
            // access public static field 'x' of Main class
            e.eval("print(M.x)");
    
            // assign to public static field 'x' of Main class
            e.eval("M.x += 10;");
    
            // change is seen from Java
            System.out.println(Main.x);
        }
    }