Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Inject.js with Acorn Fails to Parse 'for each' JavaScript Syntax for Java Objects in Nashorn Sandbox #159

Open
kumaraswamyarun opened this issue Aug 21, 2024 · 4 comments
Labels

Comments

@kumaraswamyarun
Copy link

kumaraswamyarun commented Aug 21, 2024

I am using the Delight Nashorn Sandbox with inject.js, which utilizes acorn to parse JavaScript code. When I try to use the non-standard for each loop to enumerate over a Java object, I encounter exception. as for each in nashorn is capable to enumerate java objects using for each...in.

the sanbox.eval is fully capable to parse for each...in statement but the secureJs method in the SandboxImpl fails during parsing as acorn uses ECMA standard. so tests that used to work with for each is requiring refactoring, earlier beautify js did not have this problem, since introduction of acorn which is the right way forward, but the for each is getting hit.

reference that for each has java objects enumeration capability.
https://www.programming-books.io/essential/java/usage-of-java-objects-in-javascript-in-nashorn-7cb3bcb462e4428d8ebd06cbcdf3e58b

Example code to test which fails with invalid token.

   `final NashornSandbox sandbox = NashornSandboxes.create();
    sandbox.allow("delight.nashornsandbox.internal.InterruptTest");

    // Create a Java ArrayList and add some elements
    
    final String[] fruits = new String[] {"Apple","Banana","Cherry"};
    
    // Pass the Java list to the JavaScript environment
    sandbox.inject("fruits", fruits);

    // JavaScript code to iterate over the Java list
    final String script = "var result = '';"
                  + "for each(var fruit in fruits) {"
                  + "   result += fruit + '\\n';"
                  + "}"
                  + "result;";  // Return the result

    try {
        // Evaluate the script and get the result
        final Object result = sandbox.eval(script);
        System.out.println(result.toString());
    } catch (final Exception e) {
        e.printStackTrace();
    }`
    
    
    <eval>:1:69374 SyntaxError: Unexpected token (1:20)
at org.openjdk.nashorn.internal.objects.NativeError.initException(NativeError.java:135)
at org.openjdk.nashorn.internal.objects.NativeSyntaxError.<init>(NativeSyntaxError.java:73)
at org.openjdk.nashorn.internal.objects.NativeSyntaxError.<init>(NativeSyntaxError.java:77)
at org.openjdk.nashorn.internal.objects.NativeSyntaxError.constructor(NativeSyntaxError.java:98)
at org.openjdk.nashorn.internal.scripts.Script$Recompilation$110$69281AA$\^eval\_.L:1-1#L:1#L:1#L:1#raise(<eval>:1)
at org.openjdk.nashorn.internal.scripts.Script$Recompilation$109$14789A$\^eval\_.L:1-1#L:1#L:1#L:1#unexpected(<eval>:1)
at org.openjdk.nashorn.internal.scripts.Script$Recompilation$108$14732A$\^eval\_.L:1-1#L:1#L:1#L:1#expect(<eval>:1)
at org.openjdk.nashorn.internal.scripts.Script$Recompilation$106$20069A$\^eval\_.L:1-1#L:1#L:1#L:1#parseForStatement(<eval>:1)
at org.openjdk.nashorn.internal.scripts.Script$Recompilation$63$17250AZA$\^eval\_.L:1-1#L:1#L:1#L:1#parseStatement(<eval>:1)
at org.openjdk.nashorn.internal.scripts.Script$Recompilation$62$16005A$\^eval\_.L:1-1#L:1#L:1#L:1#parseTopLevel(<eval>:1)
at org.openjdk.nashorn.internal.scripts.Script$Recompilation$48$11746$\^eval\_.L:1-1#L:1#L:1#L:1#parse(<eval>:1)
at org.openjdk.nashorn.internal.scripts.Script$Recompilation$40$13058AA$\^eval\_.L:1-1#L:1#L:1#L:1#parse-1(<eval>:1)
at org.openjdk.nashorn.internal.scripts.Script$Recompilation$39$110065AA$\^eval\_.L:1-1#L:1#L:1#L:1#parse-2(<eval>:1)
at org.openjdk.nashorn.internal.scripts.Script$Recompilation$38$110331AA$\^eval\_.L:1-1#L:1#L:1-1#exports(<eval>:1)
at org.openjdk.nashorn.internal.runtime.ScriptFunctionData.invoke(ScriptFunctionData.java:650)
at org.openjdk.nashorn.internal.runtime.ScriptFunction.invoke(ScriptFunction.java:513)
at org.openjdk.nashorn.internal.runtime.ScriptRuntime.apply(ScriptRuntime.java:520)
at org.openjdk.nashorn.api.scripting.ScriptObjectMirror.call(ScriptObjectMirror.java:111)
at delight.nashornsandbox.internal.JsSanitizer.lambda$1(JsSanitizer.java:207)
at delight.nashornsandbox.internal.JsSanitizer.injectInterruptionCalls(JsSanitizer.java:178)
at delight.nashornsandbox.internal.JsSanitizer.secureJsImpl(JsSanitizer.java:167)
at delight.nashornsandbox.internal.JsSanitizer.secureJs(JsSanitizer.java:148)
at delight.nashornsandbox.internal.NashornSandboxImpl.eval(NashornSandboxImpl.java:248)
at delight.nashornsandbox.internal.NashornSandboxImpl.eval(NashornSandboxImpl.java:225)
at com.arun.NashornJavaCollectionsExample.main(NashornJavaCollectionsExample.java:42)
@mxro
Copy link
Collaborator

mxro commented Aug 22, 2024

Hi @kumaraswamyarun Thank you for raising this issue!

I think there is a syntax issue in your JavaScript.

Can you try:

for (let i = 0; i < fruits.length; i++) {
  fruit = fruits[i];

@mxro mxro added the question label Aug 22, 2024
@kumaraswamyarun
Copy link
Author

Thank you for your prompt response mxro,

you are correct. the for each syntax is a non standard javascript but this syntax is a valid which the nashorn script engine, which is capable to enumerate java collections like HashMap, List, but its not ecma complaint. that was the point I was raising, using standard for loop we can as mentioned by you achieve the result with a little bit of manual intervention.

@mxro
Copy link
Collaborator

mxro commented Aug 24, 2024

Thanks for your response!

See below from the Nashorn documentation:

The Nashorn engine is an implementation of the ECMAScript Edition 5.1 Language Specification. It also implements many new features introduced in ECMAScript 6 including template strings; let, const, and block scope; iterators and for..of loops; Map, Set, WeakMap, and WeakSet data types; symbols; and binary and octal literals.

So the following may work for you as well:

for (const fruit of fruits) {

That's still JavaScript Syntax. As far as I know, Nashorn doesn't support Java-like syntax for loops.

Hope that helps!

@kumaraswamyarun
Copy link
Author

ok mxro.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants