[graalvm-users] Question about js.experimental-foreign-object-prototype option

Carlos Aristu carlos.aristu at openbravo.com
Fri Jul 26 05:36:25 PDT 2019


Hello Steve, Christian

  thanks for answering.

  @Steve As an alternative to your proposed solution I found the *Java.from*
function provided by GraalJS[1]. I was directly passing the Java list and
then transforming it inside the Javascript code by invoking
Java.from(myList). But finally I've taken your solution because makes my
code simpler (see below).

 @Christian Let me clarify a little bit my use case. I have a program built
in Javascript. I'm using Graal because I want to execute this program with
Java. So I need to handle data transformations in both "directions":

  1) Passing input data from Java to GraalJS (Java --> GraalJS)

       In the Java side I have a list of JSONObjects
(org.codehaus.jettison.json.JSONObject objects) that I pass to the
Javascript program. The Javascript program invokes several functions of the
Javascript Array prototype (like sort()) with the provided list. With the
*js.experimental-foreign-object-prototype* option I was able to make it
work by directly passing my JSONObject list. But being this an
"experimental" option, I would like to have a more "stable" approach. This
is my current solution (based on Steve's suggestion):

*    public Value jsonToGraal(List<JSONObject> jsonList) {*





*      Value myArray = context.eval(JavaScriptLanguage.ID, "[]");
jsonList.stream()        .map(this::jsonToGraal)        .forEach(value ->
myArray.setArrayElement(myArray.getArraySize(), value));      return
myArray;  }*



*    private Value jsonToGraal(JSONObject json) {    return
context.eval(JavaScriptLanguage.ID, "dummy = " + json.toString());  }*

  Also note that I'm using the string representation of the JSONObject with
eval to transform my JSONObject into a Javascript objects.

  2) Receiving the result of the Javascript calculation in Java (GraalJS
--> Java)

     Once the Javascript program finishes it returns a Javascript object
which I'm retrieving in Java through a polyglot Value. In this case, I need
to turn this Value into a JSONObject. This is my current solution for this
transformation:

*    public JSONObject graalToJson(Value value) {*







*    try {
context.getBindings(JavaScriptLanguage.ID).putMember("value", value);
  String jsonContent = context.eval(JavaScriptLanguage.ID,
"JSON.stringify(value)").asString();        return new
JSONObject(jsonContent);    } catch (JSONException ignore) {      return
null;    }  }*

  I also had another alternative for this which consists of using the
polyglot Value object methods to retrieve the members and create my
JSONObject manually. So far, both solutions are similar for me in terms of
performance.

  Currently all of this is working fine for me, but I'm not sure if this is
the best way of dealing with this data transformations. I would like to
know if there are any recommended alternatives to achieve this (specially
if they are better in performance). Any suggestions are very welcome.

  Thank you in advance!

[1]
https://urldefense.proofpoint.com/v2/url?u=https-3A__github.com_graalvm_graaljs_blob_master_docs_user_JavaScriptCompatibility.md-23javafromjavadata&d=DwIFaQ&c=RoP1YumCXCgaWHvlZYR8PZh8Bv7qIrMUB65eapI_JnE&r=CUkXBxBNT_D5N6HMJ5T9Z6rmvNKYsqupcbk72K0lcoQ&m=Av98W_zk2c7VEnRBSQVpPTajz98UeMxxyUxx8SRfhBI&s=lUcFYCNqY6z8pBBpBY-DspP2pQrLjC-HisODkTlrylA&e= 














[1]
https://urldefense.proofpoint.com/v2/url?u=https-3A__github.com_graalvm_graaljs_blob_master_docs_user_JavaScriptCompatibility.md-23javafromjavadata&d=DwIFaQ&c=RoP1YumCXCgaWHvlZYR8PZh8Bv7qIrMUB65eapI_JnE&r=CUkXBxBNT_D5N6HMJ5T9Z6rmvNKYsqupcbk72K0lcoQ&m=Av98W_zk2c7VEnRBSQVpPTajz98UeMxxyUxx8SRfhBI&s=lUcFYCNqY6z8pBBpBY-DspP2pQrLjC-HisODkTlrylA&e= 


El vie., 26 jul. 2019 a las 13:04, Christian Wirth (<
christian.wirth at oracle.com>) escribió:

> Hi Carlos,
>
> thank you for your question.
>
> The JavaScript language is very lenient towards what it accepts as array.
> If an object has a "length" property, it behaves like an array. What you
> provide fulfils that requirement, and can thus be sorted (and searched,
> filtered, etc.).
>
> However, what you provide does not have `Array.prototype` assigned as its
> prototype. You are basically calling `({}).sort();`, resulting in a
> TypeError in plain JS (or the "Message not supported" in Interop). From JS
> language semantics, the right thing to do would be
> `Array.prototype.sort.call(myInteropObj);`. That, however, requires a
> change in your source code and potentially libraries that you use.
>
> To mitigate that, we have the *js.experimental-foreign-object-prototype *option
> that you found already. This forces the Array.prototype on array-like
> object; however, this option might also break other code, which is why we
> don't use that behavior by default.
>
>
> The option is experimental as we are not sure yet whether this is the
> right way to go for a longer time, or whether we can support that in a
> better way in the future. In this case, `experimental` really means: there
> is no guarantee that exactly this option, with exactly this behavior, will
> exist in future releases. We are aware of the usecase though and will see
> to support it in reasonable fashion in any case.
>
> Your feedback that you are using this option is helpful to us: the more we
> know about "experimental" features being used in practice, the more we will
> see to have them as stable features.
>
> Best,
> Christian
>
>
> Am 24.07.2019 um 13:25 schrieb Carlos Aristu:
>
> Hello all,
>
>   I'm currently using GraalJS to execute some javascript functions from my
> Java code. One of this javascript functions receives an array as an
> argument and invokes the *sort()* method.
>
>   To invoke this function from Java, I'm creating an ArrayList and I send
> it to through a ProxyArray, something similar to this code snippet:
>
> *      Source sources = Source.newBuilder("js", jsCode,
> "myCode").buildLiteral();*
>
> *      Source function = Source.create("js", "myFunction"); *
> *      List<String> myList = new ArrayList<>();*
> *      try (Context context = Context.newBuilder()*
>
>
>
>
>
> *        .engine(Engine.create())         .allowHostAccess(HostAccess.ALL)
>         .build()) {           context.eval(sources);           Value res =
> context.eval(function).execute(ProxyArray.fromList(myList));     }*
>
>   That code fails with the following error: "*org.graalvm.polyglot.PolyglotException:
> TypeError: invokeMember on foreign object failed due to: Message not
> supported.*"
>
>   To make it work, I need to enable the *js.experimental-foreign-object-prototype
> *option[1] for the Context.
>
>   Being an experimental option and according to the docs, it is not
> recommended to enable it for productive environments. My questions are:
>
>   a) ¿Is there any plan to switch this option as non-experimental?
>   b) ¿Do you know if there exists any alternative (or a better way) to
> provide a JS array as an argument of a JS function from Java?
>
> Thank you in advance.
>
> [1] https://urldefense.proofpoint.com/v2/url?u=https-3A__github.com_graalvm_graaljs_issues_88-23issuecomment-2D453021299&d=DwIFaQ&c=RoP1YumCXCgaWHvlZYR8PZh8Bv7qIrMUB65eapI_JnE&r=CUkXBxBNT_D5N6HMJ5T9Z6rmvNKYsqupcbk72K0lcoQ&m=Av98W_zk2c7VEnRBSQVpPTajz98UeMxxyUxx8SRfhBI&s=uUOBwgr-5a1lIk-NL23PC1WiPcnMf9zwnhXKLc8hyTg&e= 
> <https://urldefense.proofpoint.com/v2/url?u=https-3A__github.com_graalvm_graaljs_issues_88-23issuecomment-2D453021299&d=DwMFaQ&c=RoP1YumCXCgaWHvlZYR8PZh8Bv7qIrMUB65eapI_JnE&r=CUkXBxBNT_D5N6HMJ5T9Z6rmvNKYsqupcbk72K0lcoQ&m=SONxRA-cJWH4INLX-uDgL1Afx7XABorqPK3ite36VtA&s=Hw4Fpfxv8qQMK9XrdAcEW49J5nMi0ODhnsFdecPww3U&e=>
> --
>
> <https://urldefense.proofpoint.com/v2/url?u=https-3A__www.openbravo.com&d=DwMFaQ&c=RoP1YumCXCgaWHvlZYR8PZh8Bv7qIrMUB65eapI_JnE&r=CUkXBxBNT_D5N6HMJ5T9Z6rmvNKYsqupcbk72K0lcoQ&m=SONxRA-cJWH4INLX-uDgL1Afx7XABorqPK3ite36VtA&s=qLyjnBLTJ0nP65gCeCPRY2IqJC0l9sOfxepjQ0AnXfM&e=>
> Carlos Aristu López
> Applications Engineer
>
> *This e-mail is confidential and contains private information. Any
> reading, retention, distribution or copying of this communication by any
> person other than its intended recipient is prohibited.*
>
> *Your data is processed by Openbravo under our privacy policy
> <https://urldefense.proofpoint.com/v2/url?u=https-3A__www.openbravo.com_privacy-2Dpolicy_&d=DwMFaQ&c=RoP1YumCXCgaWHvlZYR8PZh8Bv7qIrMUB65eapI_JnE&r=CUkXBxBNT_D5N6HMJ5T9Z6rmvNKYsqupcbk72K0lcoQ&m=SONxRA-cJWH4INLX-uDgL1Afx7XABorqPK3ite36VtA&s=S2N4L5FShXFXrm0d1AT3OyWLXYYH51PCWsdofw_twng&e=>*
>
> _______________________________________________
> GraalVM-Users mailing listGraalVM-Users at oss.oracle.comhttps://oss.oracle.com/mailman/listinfo/graalvm-users
>
> _______________________________________________
> GraalVM-Users mailing list
> GraalVM-Users at oss.oracle.com
> https://oss.oracle.com/mailman/listinfo/graalvm-users



-- 
<https://urldefense.proofpoint.com/v2/url?u=https-3A__www.openbravo.com&d=DwIFaQ&c=RoP1YumCXCgaWHvlZYR8PZh8Bv7qIrMUB65eapI_JnE&r=CUkXBxBNT_D5N6HMJ5T9Z6rmvNKYsqupcbk72K0lcoQ&m=Av98W_zk2c7VEnRBSQVpPTajz98UeMxxyUxx8SRfhBI&s=92BdYf5XGnh1ZH_JLABVzFfoITnqmapW4yzu6DOE1XI&e= >
Carlos Aristu López
Applications Engineer

*This e-mail is confidential and contains private information. Any reading,
retention, distribution or copying of this communication by any person
other than its intended recipient is prohibited.*

*Your data is processed by Openbravo under our privacy policy
<https://urldefense.proofpoint.com/v2/url?u=https-3A__www.openbravo.com_privacy-2Dpolicy_&d=DwIFaQ&c=RoP1YumCXCgaWHvlZYR8PZh8Bv7qIrMUB65eapI_JnE&r=CUkXBxBNT_D5N6HMJ5T9Z6rmvNKYsqupcbk72K0lcoQ&m=Av98W_zk2c7VEnRBSQVpPTajz98UeMxxyUxx8SRfhBI&s=tkGcYufAInp_ieW7JNvw1x0Olis5vwVHtxg578-lWFU&e= >*
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://oss.oracle.com/pipermail/graalvm-users/attachments/20190726/c7b7f008/attachment-0001.html 


More information about the GraalVM-Users mailing list