Collectives™ on Stack Overflow
Find centralized, trusted content and collaborate around the technologies you use most.
Learn more about Collectives
Teams
Q&A for work
Connect and share knowledge within a single location that is structured and easy to search.
Learn more about Teams
I am developing a Java application that needs to execute
JavaScript. Nashorn JS engine is about to get deprecated
and the replacement is the set of APIs provided by Graal SDK
which makes use of GraalVM. The virtual machine that essentially
executes a number of languages.
At least that is what I think.
So I spent a day trying to get it working. I downloaded GraalVM rc6 that uses JDK 8. I use IntelliJ IDEA and I added GraalVM as a new JDK. I found it strange that I am supposed to add a virtual machine as a development kit, but I knew it is based on JDK 8 so I was ok with it.
And the problem was unlike others, I could not get the new packages to work. My IDE told me it cannot resolve them.
Actually, none of the org.graalvm packages could be resolved.
So I downloaded JDK 11 build 28 because as far as I know JDK 11 comes with GraalVM since build 20.
Actually, in this case, some of the packages could be found, but far less than expected: for instance org.graalvm.polyglot still could not be resolved.
Finally, I tried adding Graal SDK from Maven and the packages were resolved. Now I get an exception when running:
Context ctx = Context.create(“js”);
No language and polyglot implementation were found on the classpath. Make sure the truffle-api.jar is on the classpath.
I thought the problem in the first 2 cases was actually not acquiring GraalVM JDK, but it throws the exception even this way.
Can someone experienced explain the matter?
GraalVM
GraalVM is a high-performance embeddable polyglot virtual machine currently
supporting a number of programming languages: Java (and JVM languages),
JavaScript (including node.js), Ruby, R, Python, and C/C++ and other languages
with the LLVM backend.
You can download the pre-built distribution of GraalVM here:
https://www.graalvm.org/downloads.
Among other things it includes a java runtime, a node runtime, a JavaScript engine called Graal.js, etc.
Graal SDK is the polyglot API allowing GraalVM to work with all the language implementations it can run.
This polyglot API is packaged as a jar file: $GRAALVM_HOME/jre/lib/boot/graal-sdk.jar
.
Adding that file as an external library to your IDEA project / module, would allow the IDE to find the classes like:
org.graalvm.polyglot.Context
and org.graalvm.polyglot.Value
which are necessary to interop with the languages, including
the JavaScript implementation.
If your project is using Maven, you can add a system dependency on that file, and maven will find it on any system where
$JAVA_HOME
is set to point at a GraalVM distribution.
<dependency>
<groupId>org.graalvm</groupId>
<artifactId>graal-sdk</artifactId>
<version>1.0.0-rc</version>
<scope>system</scope>
<systemPath>${java.home}/lib/boot/graal-sdk.jar</systemPath>
</dependency>
Now when you will run the java
command from the GraalVM distribution, the necessary files will be added to the classpath automatically.
So nothing more is necessary to run something like the following in the IDE:
import org.graalvm.polyglot.*;
public class Main {
public static void main(String[] args) {
Context polyglot = Context.create();
Value array = polyglot.eval("js", "[1,2,42,4]");
System.out.println(array.getArrayElement(2).asInt());
Now this is because GraalVM has the Graal.js JavaScript engine enabled by default.
If you want to run it on a stock JDK you need to add more things to the classpath.
Running Graal.js on a stock JDK**
There's this question on how to run Graal.js on the stock JDK: How to use graaljs ? Is there a place where to get a .jar file/files?.
The accepted answer tells in more details where to find the necessary jar files to make it work on Java 8.
In a nutshell you need to add the following jar files to the classpath to make it actually run:
graal-sdk.jar - GraalVM polyglot API
truffle-api.jar - API for language implementations.
graaljs.jar - this is the implementation of GraalVM's JavaScript Engine
graaljs-scriptengine.jar -- allows to use Graal.js through the Java script engine API.
graaljs-launcher.jar
tregex.jar -- regexp library
truffle-profiler.jar - profiler for Truffle languages implementations
chromeinspector.jar - debugger integration
launcher-common.jar
You can find them in the GraalVM distribution that you downloaded, both editions would work fine.
Now without the Graal compiler the performance of the JavaScript engine would not be optimal.
As you mentioned yourself JDK 11 comes with a snapshot of the Graal compiler (not GraalVM, which is a full distribution of the GraalVM project including JS engine, LLVM bitcode interpreter, node implementation, JVM, etc). You can enable the Graal compiler by passing
--XX:+UnlockExperimentalVMOptions --XX:+UseJVMCICompiler
to the java
command.
Now running it all on JDK 11 might not work because JDK 11 is sufficiently different from JDK 8 and there could be problems with the module system or things missing (like jax-b), but it also might work. It would work on JDK 8.
So I found out the problem. IntelliJ IDEA is so much used to
the standard JDK Home structure that it was not loading the
the Graal SDK and other apis.
The Maven jar files that got me closer to the result were
EXACTLY the same files that were bundled with GraalVM.
IntelliJ is not adding all of the Jars from the Graal SDK to your classpath.
You can add the Jars to your classpath inside IntelliJ by navigating to
File > Project Structure > SDKs > Choose your Graal SDK
Then click the +
button at the bottom to add the Jar files. Adding the graal-sdk.jar will fix the problem with finding the org.graalvm
package.
This will avoid having to modify your pom.xml
file to fix a problem with the IDE.
Using both IntelliJ (2020.2) and GraalVM (graalvm-ce-java11-20.3.0) I was able make the following code work:
public static void main(String[] a0rgs) {
System.out.println("Hello World!");
Context context = Context.create();
context.eval("js", "console.log('hello from javascript');");
Just by adding this dependency to maven
:
<dependency>
<groupId>org.graalvm.sdk</groupId>
<artifactId>graal-sdk</artifactId>
<version>20.3.0</version>
</dependency>
Just as an up-to-date answer which works in 2023 with Gradle and without the need of GraalVM itself but in the standard OpenJDK.
I simply added
dependencies {
implementation 'org.graalvm.sdk:graal-sdk:22.3.0'
implementation 'org.graalvm.js:js:22.3.0'
implementation 'org.graalvm.js:js-scriptengine:22.3.0'
to my build.gradle
and it works without any hassle in OpenJDK.
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.