fusionlightcat fusionlightcat - 6 months ago 23
Java Question

Nashorn: How to pre-set Java.type()-vars inside of Java before JavaScript execution?

I am currently executing my JavaScript-scripts with this java code:

ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");
engine.eval(new FileReader("awesome_script.js"));


I need to call Java functions from JavaScript, so I defined this at the top of my
awesome_script.js
file:

var first = Java.type('io.github.awesomeprogram.FirstClass');
var second = Java.type('io.github.awesomeprogram.SecondClass');
var extra = Java.type('io.github.awesomeprogram.ExtraClass');


I can then call some methods from these classes, e.g.:

second.coolmethod("arg1",2);


My problem is now that I need to use many java classes inside of my scripts. I also have a lot of scripts and I think it is very inefficient to define every single one of this classes in every script.

So I am looking for a solution to create the objects created inside of JavaScript with
Java.type()
inside of Java and then pass them to the script I want to execute.

How can I do this?

Thanks in advance!

Answer

After quite a bit of research I found a way to put global variables in the ScriptEngine before executing: The Java Scripting API (Oracle Docs)

This enabled me to put any object I want into a global variable. However, I still needed a way to get the Object that Java.type() creates inside of Java. So I wrote a test script which returns one of this objects and I found out it is an object of the type jdk.internal.dynalink.beans.StaticClass. This class has an constructor which takes a ordinary Class as an argument. Sadly, this constructor is not usable in my code because it is not visible. To bypass this I used reflection and made this method:

public StaticClass toNashornClass(Class<?> c) throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException{

    Class<?> cl = Class.forName("jdk.internal.dynalink.beans.StaticClass");

    Constructor<?> constructor = cl.getDeclaredConstructor(Class.class);

    constructor.setAccessible(true);
    StaticClass o = (StaticClass) constructor.newInstance(c);

    return o;
}

If I pass the Class of the object I want as a global variable I just need to call toNashornClass(Example.class); and put the resulting object into a global var with engine.put("example",object);

It works fine. I can use the example var completely like a var created by Java.type().

Comments