Search code examples
graalvm

Injected members from the host language to arrive to guest language as guest language types


This question is somewhat related to: GraalVM - Using Polyglot Value without a context

In my application, the code snippets run in the guest languages should not need to know that the arguments injected (through members of the bindings) are Java arguments. Instead, for people developing in the guest language, arguments should look like just another argument of the guest language itself.

For example, I would like for an array injected from my Java host language to a JS guest script, in this fashion:

Value guestLanguageBindings = context.getBindings(scriptData.getLanguage().toString());

guestLanguageBindings.putMember(argumentName, argumentValue);

to "arrive" to the guest language as a JS array, not as a java.util.ArrayList as it is happening right now.

Currently I got around this problem by converting every non primitive type (I noticed that String, int, etc. arrive to JS as JS "types") to JSON and converting back in the guest language.

This works, but I wonder if there is a more appropriate way to do it or if indeed using the bindings is the right way to go?

Thanks!


Solution

  • The answer provided by @Christian Humer suggesting to use ProxyArray is a good one, and is explanation on how to put together a ProxyArray is correct and well presented.

    However, my requirement was to be able to present the array argument (set using the top level bindings) as if it was a guest language data type. ProxyArray only get me halfway there, with the resulting data type being a Java type and not for example a JS type.

    In order to fully achieve the above, since I am in control of the Java host side, I have created up-front a JS array using the Context, on the host side, and copied the content of the Java ArrayList in it. When calling the guest code, I simply set the JS array in the bindings, which is already a fully featured JS array.

        Value jsArray = context.eval("js", "new Array();");
    
        jsArray.setArrayElement(0, 1001); //array will grow automatically, JS semantics
        jsArray.setArrayElement(1, 1002);
        jsArray.setArrayElement(2, 1003);
    
        guestLanguageBindings.putMember("variable", jsArray);
        context.eval("js", "print(variable);");
    

    This approach was suggested to me on Github when I filed the bug report mentioned in the comments above.