soundslikeodd
soundslikeodd

Reputation: 1077

Script engine giving error when evaluating Scala script in Java

I have a app that executes scala scripts that get passed to it. The following is an example of how I am attempting to execute the scala code.

String script = "println(\"Hello World!\")";
ScriptEngine scriptEngine = new ScriptEngineManager().getEngineByName("scala");
scriptEngine.eval(script);

I get the following error.

[init] error: error while loading Object, Missing dependency 'object scala in compiler mirror', required by /Library/Java/JavaVirtualMachines/jdk1.7.0_80.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.

I am using Java 7 (jdk1.7.0_80.jdk) on a Mac. I am running this from within a spring-boot app.

Scala maven dependency used.

<dependency>
    <groupId>org.apache.clerezza.scala</groupId>
    <artifactId>script-engine</artifactId>
    <version>1.0.0</version>
</dependency>

Why am I getting this error?

Upvotes: 1

Views: 1964

Answers (1)

Mohsen_Fatemi
Mohsen_Fatemi

Reputation: 3391

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:

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 {
          ....
          ((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 need the Scala libraries in 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

Upvotes: 6

Related Questions