DEV Community

Bhaskar Gupta
Bhaskar Gupta

Posted on

Running your JavaScript/Python scripts in Java

Java is evolving; that's cool.

[A brief show-off; skip to the next section if you are already a Java evangelist]

After the acquisition of Java by Oracle Corporation in 2010 with the launch of Java 7 a.k.a. Project Dolphin, it was an affirmation of the Oracle's commitment to the language and technology. It was a big achievement for the tech giant's two year ownership of Sun Microsystems - the company that gave birth to Java programming language.
With Java SE 8 a.k.a Project Spider, came various major tweaks and upgrades to the Java programming language including significant upgrade to the functional programming called the Lambda Expressions, new and improved Date/Time API, an enhanced JavaScript Engine, new streaming API and much more, thereby being a revolutionary release of the development platform.

With such fast paced recurrent releases with major improvements and with easy and effective migration, Java is the language here to stay.

JSR 223

Java Specification Request, the actual descriptions of proposed and final specifications for the Java platform, JSR 223 proposed the much debated issue between the developers who used scripting languages and the ones you used Java as the primary language, only because of difficulty of integration, so much so that they had to stick to either of them. With Java 6, this issue was resolved via the launch of the Scripting API, which improved with the advent of Java 8. By default, the engine present is nashorn, but more can be added by downloading relevant engines.

Up until now more than 2 dozen engines have been implemented.

In this article we'll discuss about the Project Nashorn (previously Project Rhino) which is the scripting engine for JavaScript.

The entire scripting API is contained in the package javax.script.

This lightweight package contains six interfaces:

  • Bindings
  • Compilable
  • Invocable
  • ScriptContext
  • ScriptEngine
  • ScriptEngineFactory

five classes:

  • AbstractScriptEngine
  • CompiledScript
  • ScriptEnginemanager
  • SimpleBindings
  • SimpleScriptContext

and a single exception:

  • ScriptException

Script Engine

The two key classes for our use,

  1. ScriptEngineManager : Responsible for discovery of a script engine and stores data in context to allow it to be shared with programs. Data can be stored as key/value pairs and made available for all script engines. They should be considered as global data.

  2. ScriptEngine : This is an interface available part of java api. This should be implemented separately for every scripting language. For javascript in the Oracle JDK (from 1.6) by default an implementation is available.

Apache commons provides a project Jakarta Bean Scripting Framework (BSF) which gives implementation for a several set of scripting languages like Python, TCL, NetRexx including JavaScript and lot more.

Basic Implementations

We'll start by basic implementations of JavaScript using the nashorn engine to get an understanding of how it really works out to be.

  • Taking a script as the direct input.

Output as:

30

Here print(10+20) directly passed as String, works like a script.

By simply creating instance of ScriptEngineManager and then defining the engine, we can use ScriptEngine's eval() method to run scripts.

  • Running multiple lines of script in one go.

Output as:

30

ScriptEngine eval() method can be used to run multiple scripts as one block as well.

  • Reading JavaScript files

Output is :

Hello World from JavaScript

where HelloWorld.js is

This way one can read the JavaScript file by calling the file by using FileReader and run as per requirement.

  • Using individual functions defined in JavaScript file

One can define various functions in JavaScript and use them as independent methods in the Java program.

For this Invocable interface has to be implemented which is stored in the same package javax.script

For example let us take a JavaScript file containing various methods having arithmetic operations : add, subtract, multiply.

We can create the instances of ScriptEngineManager and ScriptEngine to be static if we have to service multiple requests so that they are implemented as soon as the file is loaded but as far as the eval() method is concerned that is, the process of calling the JavaScript file, that has to be done either every time the required method is called or directly in the main method.

Output is:

5.0
1.0
6.0

Using Invocable, one has to pass in the name of the function as a string and then the arguments that it would require as per the implementation in the JavaScript file.

These are the key basic steps and ways to run JavaScript scripts using Java.

TL;DR

Discussed basic steps to execute JavaScript scripts in Java using Java ScriptEngine's engine Nashorn.

Create instance of ScriptEngineManager to initialise the scripting engine as an instance of ScriptEngine. Use eval method to directly run the script by passing in as strings or read the JavaScript file. Implement Invocable to call in methods defined in the JavaScript file as per request.
This blog post was written during my Google Summer of Code 2019 project with JBoss Community, ScriptEngine integration with WildFly Elytron in which I added custom implementation for components of WildFly Elytron in scripting languages.

Top comments (0)