Use import in javascript being called from Java program through graalvm

725 Views Asked by At

I am trying out Graalvm for a use case and I was wondering if I can use import statements in the javascript being called from java. I have tried both:

context.eval("js", "import v4 from 'uuid';var o = v4();");

which gives the error Expected an operand but found import import v4 from 'uuid';var o = v4();

and

creating a separate script containing

import v4 from 'uuid';
var uu = v4();

then running the script via

InputStream inputStream = Controller.class.getResourceAsStream("/script.js");
String script = IOUtils.toString(inputStream, StandardCharsets.UTF_8);
context.eval("js", script);

which returns the same error: Expected an operand but found import import v4 from 'uuid';

I went through the docs and it seems like it is possible. Can someone please guide me towards the correct approach?

1

There are 1 best solutions below

0
On

In case somebody is still interested, the code below is tested with Eclipse running on Windows 10. (Note double escaped backslashes) Of course, you should have both GraalVM and GraalJS installed.

import java.io.IOException;
import org.graalvm.polyglot.*;

public class testGraalJS {

    public static void main(String[] args) {
         System.out.println("Hello Java!");
         
         String src = "import {Foo} from 'C:\\\\Other\\\\foo.mjs';" +
                 "const foo = new Foo();" +
                 "console.log('Hello JavaScript!');" +
                 "console.log('Square of 42 is: ' + foo.square(42));";
         
         Engine engine = Engine.newBuilder()
                 .option("engine.WarnInterpreterOnly", "false")
                 .build();
         
         Context ctx = Context.newBuilder("js")
                 .engine(engine)
                 //.allowHostAccess(HostAccess.ALL) /*not needed for this example */
                 .allowHostClassLookup(className -> true)
                 .allowIO(true)
                 .build();
         
         try {
            Source source =  Source.newBuilder("js", src, "script.mjs").build();
            ctx.eval(source);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
         
    }

}

Where foo.mjs is located in folder C:/Other with the following content:

export class Foo {

    square(x) {
        return x * x;
    }
}

Output:

Hello Java!
Hello JavaScript!
Square of 42 is: 1764

Classpath in Eclipse:

Eclipse classpath

Where graal-sdk-xx.x.x.jar is downloaded separately from maven repo.

Docs.

Part 2. In case you want to source Javascript from a file:

import java.io.*;
import java.io.IOException;
import org.graalvm.polyglot.*;

public class testGraalJSfile {

    public static void main(String[] args) {
        System.out.println("Hello Java!");

        // Therefore, any ECMAScript module should have file name extension .mjs 
        // Option 1: 
        // Use source file with extension .mjs like 
        // File file = new File("C:\\Other", "source.mjs");
        //
        // In case file is with extension .js see Option 2 below
        
        File file = new File("C:\\Other", "source.js");

        String language;
        Source source = null;
        
        // Alternatively, the module Source should have Mime type "application/javascript+module" 
        // Option 2: 
        // add following line: Source.mimeType("application/javascript+module")
        
        try {
            language = Source.findLanguage(file);
            source = Source.newBuilder(language, file)
                    .mimeType("application/javascript+module")
                    .build();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        
        Engine eng = Engine.newBuilder()
                 .option("engine.WarnInterpreterOnly", "false")
                 .build();
         
        Context ctx = Context.newBuilder("js")
                 .engine(eng)
                 .allowHostAccess(HostAccess.ALL)
                 .allowHostClassLookup(className -> true)
                 .allowIO(true)
                 .build();
         
         ctx.eval(source);
         ctx.close();
         
    }

}

See here.