Run Node.js on the JVM

Published on August 16, 2016

Run Node.js on the JVM

Original author: Ian Bull
  • Transfer

Gone are the days when entire companies depended on one technology provider. Even small companies and amateurs will find the best solution for themselves, combining technology in one project. For a long time Java held the lead among server technologies. But today Node.js is everywhere.



But even with the growing popularity of Node.js and JavaScript, Java does not lose power. In addition, few organizations can afford to migrate the entire platform from the JVM to Node.js. This means that the company must either continue to use the current technology stack, or launch several stacks that will communicate through the network API. However, there is another way: run Node.js directly in the JVM process. And J2V8 finally made it possible.


J2v8



J2V8 is a set of V8 connectors for Java. J2V8 packs V8 as a dynamic library and provides the Java API for V8 through the Java Native Interface (JNI). With J2V8, you can execute JavaScript using V8 just as if you were using Rhino or Nashorn.


Initially, J2V8 was designed to provide high-performance JavaScript in Tabris.js, a cross-platform mobile library.


Over the past months, I have configured the assembly of Node.js as a dynamic library and provided interaction with the Java API for it. Now you can execute scripts for Node.js directly from Java. Unlike other solutions that try to implement Node.js using other engines, this is a real Node.js with all the bugs and features. Node.js starts in the same process as the JVM and all interaction occurs synchronously through the JNI.


Sharing Node.js and JVM


J2V8 provides an API for executing scripts in Node.js, calling JavaScript functions from Java and vice versa, connecting NPM modules, and starting the Node.js message queue. All Node.js kernel modules are also present.


Running Node.js on the JVM makes it easier to migrate for anyone who uses the large Java stack, but wants to start using Node.js. For example, you can run a server (such as Express.js) on Node.js and call existing Java methods to process requests.


static String NODE_SCRIPT = "var http = require('http');\n"
  + ""
  + "var server = http.createServer(function (request, response) {\n"
  + " response.writeHead(200, {'Content-Type': 'text/plain'});\n"
  + " response.end(someJavaMethod());\n"
  + "});\n"
  + ""
  + "server.listen(8000);\n"
  + "console.log('Server running at http://127.0.0.1:8000/');";
public static void main(String[] args) throws IOException {
  final NodeJS nodeJS = NodeJS.createNodeJS();
  JavaCallback callback = new JavaCallback() {
    public Object invoke(V8Object receiver, V8Array parameters) {
      return "Hello, JavaWorld!";
    }
  };
  nodeJS.getRuntime().registerJavaMethod(callback, "someJavaMethod");
  File nodeScript = createTemporaryScriptFile(NODE_SCRIPT, "example");
  nodeJS.exec(nodeScript);
  while(nodeJS.isRunning()) {
    nodeJS.handleMessage();
  }
  nodeJS.release();
}

NPM


In addition to calling existing Java methods from Node.js, J2V8 provides the ability to call JavaScript functions (including NPM modules) directly from Java. With this integration, Java users can immediately start using NPM modules directly in the JVM. For example, you can use jimp to process images in Java.


public static void main(String[] args) {
  final NodeJS nodeJS = NodeJS.createNodeJS();
  final V8Object jimp = nodeJS.require(new File("path_to_jimp_module"));
  V8Function callback = new V8Function(nodeJS.getRuntime(), new JavaCallback() {    
    public Object invoke(V8Object receiver, V8Array parameters) {
      final V8Object image = parameters.getObject(1);
      executeJSFunction(image, "posterize", 7);
      executeJSFunction(image, "greyscale");
      executeJSFunction(image, "write",  "path_to_output");
      image.release();
      return null;
    }
  });
  executeJSFunction(jimp, "read", "path_to_image", callback);
  while(nodeJS.isRunning()) {
    nodeJS.handleMessage();
  }     
  callback.release();
  jimp.release();
  nodeJS.release();
}

J2V8 connection


Integration with Node.js is already available in J2V8 (version 4.4.0). You can use it on Windows (32-bit and 64-bit), MacOS and Linux (64-bit). Use the following dependency in pom to get it from Maven Central (this example is for Windows 64's, don't forget to swap for other platforms):


<dependency>
  <groupId>com.eclipsesource.j2v8</groupId>
  <artifactId>j2v8_win32_x86_64</artifactId>
  <version>4.4.0</version>
</dependency>

From translator


J2V8 gives us a new level of abstraction, allowing us to choose the most suitable technology for each individual task within the whole project. As a developer, I have always been attracted by the reliability of Java and the convenience of Node.js. And, soon, I hope that we will see examples of successful projects combining the best of both worlds.