Scripting Scala – JSR-223

With the release of Scala 2.11 it became fully JSR-223 compliant scripting language for Java. JSR-223 is the community request to allow scripting language to have an interface to Java and to allow Java to use the scripting language inside of applications.

In Java 8 the Nashorn scripting engine was released as a native component of the JDK to support JavaScript with applications. This is possible through another JSR in Java 7 – namely JSR-229, which brings support for invoke dynamics, a way to support dynamic programming by the Java byte code compiler. Nashorn can be seen as a proof of concept of this newly added functionality.

Running Scala Script in Java Application

Let’s make a simple example to execute Scala as a script inside of a Java application.

We need to import and initialize the script engine like this:

import javax.script.*;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;

public class TestScript {

    public static void main(String... args) throws Exception {
        ScriptEngine engine = new ScriptEngineManager().getEngineByName("scala");

...

With ScriptEngineManager().getEngineByName(“scala”)  a matching script engine is looked up. This just gives us the engine but not the required libraries and hooks to really execute a script.

There is one thing to note about the way Scala loads the required standard classes for the JVM. In case of the execution of scala standard Scala libraries are placed in the classpath of the JVM. This would not be the case here. You can read this for a reference. Trying to run a sample class would result in the following exception:

reflect.jar:. TestScript
[init] error: error while loading Object, Missing dependency 'object scala in compiler mirror', required by /Library/Java/JavaVirtualMachines/jdk1.8.0_65.jdk/Contents/Home/jre/lib/rt.jar(java/lang/Object.class)

Failed to initialize compiler: object scala in compiler mirror not found.
** Note that as of 2.8 scala does not assume use of the java classpath.
** For the old behavior pass -usejavacp to scala, or if using a Settings
** object programmatically, settings.usejavacp.value = true.
Exception in thread "main" scala.reflect.internal.MissingRequirementError: object scala in compiler mirror not found.

We can work around this by using the scala java tools helping us to load the standard Scala libraries into the JVM classpath. This is one way to make our Scala script work:

mport javax.script.*;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;

import scala.tools.nsc.interpreter.IMain;
import scala.tools.nsc.settings.MutableSettings.BooleanSetting;

public class TestScript {

    public static void main(String... args) throws Exception {
          ....
          ((BooleanSetting)(((IMain)engine).settings()
                               .usejavacp())).value_$eq(true);

....

The other is to simply execute the code with the following option:

$ java -Dscala.usejavacp=true ...

The complete script is this:

import javax.script.*;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;

import scala.tools.nsc.interpreter.IMain;
import scala.tools.nsc.settings.MutableSettings.BooleanSetting;


public class TestScript {

    public static void main(String... args) throws Exception {
        ScriptEngine engine = new ScriptEngineManager().getEngineByName("scala");

        ((BooleanSetting)(((IMain)engine)
               .settings().usejavacp()))
                    .value_$eq(true);

        String testScript = "var a:Int =  10";
        engine.eval(testScript);

        String testScript2 = "println(a)";
        engine.eval(testScript2);

        String testScript3 = "println(a+5)";
        engine.eval(testScript3);
    }

Compiling and running this is pretty straight forward as we do need the Scala libraries they get places into the classpath.

Compiling:

$ javac -cp /Users//hkropp/bin/scala-2.11.7/lib/scala-library.jar:
/Users//hkropp/bin/scala-2.11.7/lib/scala-compiler.jar:
/Users//hkropp/bin/scala-2.11.7/lib/scala-reflect.jar 
TestScript.java

Running:

$ java -Dscala.usejavacp=true -cp /Users//hkropp/bin/scala-2.11.7/lib/scala-library.jar:
/Users//hkropp/bin/scala-2.11.7/lib/scala-compiler.jar:
/Users//hkropp/bin/scala-2.11.7/lib/scala-reflect.jar:. 
TestScript
10
15

Further Readings

Advertisement

One thought on “Scripting Scala – JSR-223

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s