GraalVM with JPA-based applications (Part 1)
First of all, Happy New Year 2019 to each and every single one of you, dear readers!!!
I wanted to start the first technical blog post of this new year with one particular piece of JVM-related project I discovered last year and am really enthusiastic about: GraalVM, from Oracle.
In a nutshell, GraalVM is a (still experimental) very powerful polyglot virtual machine aiming at supporting and mixing different programming languages in a same application. It currently supports languages such as:
- JVM-based languages, like Java, Kotlin, Groovy, Scala, Clojure
- LLVM-based languages, such as C and C++
You see how awesome this can be?! Using GraalVM, it should be possible for example to call Ruby code from a C++ program, and share cross-language data structures.
For JVM-based applications, GraalVM also provides the following capabilities:
- a brand-new efficient Just-In-Time (JIT) compiler. As a reminder, Java code is compiled to bytecode (the famous .class files), which can be seen as an idealized platform-agnostic code, which is then interpreted by the JRE, and later compiled on the fly into machine code as the application runs; hence the terms “just in time”. Unlike the default HotSpot JIT compiler, which is written in C++ (but criticized as hard to maintain and extend), the Graal JIT compiler is written in Java, as a concrete implementation of a new interface in the JVM called the JVMCI - the JVM compiler interface - introduced in JDK 9.
- an Ahead-Of-Time (AOT) compiler to improve startup times. Unlike a JIT compiler, an AOT compiler analyzes the code up-front (along with all its dependencies) and produces a standalone platform-specific binary program. To emulate the capabilities of the JVM (such as garbage collection), the Graal AOT compiler produces Native Images that leverage Substrate VM, a Java-based framework that is also shipped with GraalVM.
The goal of this blog post is to go beyond the basic HelloWorld program, and see how we can leverage GraalVM against a sample real-world JPA-based application, able to interact with a database. We will walk through what can be done along with the potential limitations.
As always, the code for this blog post is available at Github://rm3l/jpa-graalvm.
We will be using DataNucleus as the JPA implementation, though the example project contains a set of Maven Profiles allowing to use other JPA implementations, such as EclipseLink (the reference one) or Hibernate.
Once done, you can list all JDKs available with the following command:
Installing GraalVM is then just as easy as picking the right JDK, e.g.:
You may choose to make it your default JDK system-wide, or use it temporarily just for testing:
Let’s check the JDK we have just installed and confirm we are using GraalVM:
Using the Graal Compiler
Our sample project makes use of the Java Persistence API - JPA - to persist and update few people data in an in-memory database. It then pretty-prints such records in JSON on the standard output, using the Ruby programming language, in order to showcase how polyglot GraalVM is.
This is done in the following code snippet:
What this code does is pretty straightforward:
- creating an execution context for the “ruby” language. For this, we may need to install the engine for such language using the gu (Graal Updater) command. More on that below.
- evaluating the provided Ruby script and wrapping the result in a language-agnostic org.graalvm.polyglot.Value object, which is then manipulated back in Java and printed to screen
First, let’s build the project:
Running with the optimized Graal JIT compiler is then straightforward:
If we run the command above, we may get an error indicating that the ‘ruby’ language is not installed:
In this case, we need to install the Ruby language engine, using Graal’s gu (Graal Updater) command:
Re-runing the java command above will then pretty-print our database records using Ruby code in our Java code:
That’s it for the moment, now that we have seen how we can easily leverage GraalVM to write polyglot code that extends JPA-based applications. In the second part of this blog post, we’ll see how we can further improve startup time by building a Native Image of our JPA-based application, if at all possible.
Stay tuned for the upcoming blog post, and as always, your feedback is more than welcome.