Skip to content

Instantly share code, notes, and snippets.

@takawitter
Last active March 12, 2021 10:38
Show Gist options
  • Star 8 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save takawitter/5479445 to your computer and use it in GitHub Desktop.
Save takawitter/5479445 to your computer and use it in GitHub Desktop.
The sample code to run scala via JSR223 API. I turn usejavacp option true at line 10. Unless that you have to use http://github.com/rjolly/jarlister to list classes in scala-library.jar into MANIFEST.MF of jar that contains this ScalaTest class. I use Scala-2.11.6 to run this code.
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import scala.tools.nsc.interpreter.IMain;
import scala.tools.nsc.settings.MutableSettings.BooleanSetting;
public class ScalaTest {
public static void main(String[] args) throws Exception{
ScriptEngine engine = new ScriptEngineManager().getEngineByName("scala");
((BooleanSetting)(((IMain)engine).settings().usejavacp())).value_$eq(true);
// or
// ((scala.tools.nsc.interpreter.IMain)engine).settings().processArgumentString("-usejavacp");
engine.put("n: Int", 10);
System.out.println("---");
engine.eval("1 to n foreach print");
}
}
@takawitter
Copy link
Author

execution result(stdout):

n: Int = 10

---
12345678910

@rjolly
Copy link

rjolly commented Apr 30, 2013

Hi Takao,
Instead of usejavacp, you can list scala_library.jar classes into its manisfest with either jarsigner or (better) http://github.com/rjolly/jarlister . The interpreter runs with the usemanifestcp option by defaut and the library will be included in the classpath through this mechanism.
Regarding variable bindings, they are available in 2.11-M2 but through a unique variable "bindings" which is a map of all bound variables to their values. This is improved in forthcoming versions where bound variable are accessible by their own name.

@takawitter
Copy link
Author

Thanks for your comment, rjolly!

For the classpath, even using manifest, a problem still exists when we are developing web application. The web application places classes to its WEB-INF/class folder and jars to its WEB-INF/lib folder, and scala-jsr223 doesn't have the function to recognize those classes (and no guarantee for the web-app container to read manifest).

I could use binded variable through bindings such like:

engine.getBindings(ScriptContext.ENGINE_SCOPE).put("n", 10);
1 to bindings.get("n").asInstanceOf[Int] foreach { print(_) }

Let me note requirements about variable bindings of scala-jsr223.

  • support bindings through ScriptEngine#eval(script(or reader), bindings) method.
  • support bindings through ScriptEngine#put(name, value) method.
  • guess the type of variable (return value of Object#getClass or Any if the class is not public).

Anyway, I'm looking forward to next release and will test jsr223 compliant when its available.

thanks.

@takawitter
Copy link
Author

I updated the code to use binding with type -> engine.put("n: Int", 10);
I found it accidentally 😄

@ctrueden
Copy link

ctrueden commented Apr 6, 2016

@takawitter Thank you very much for this helpful gist! This is the only place I found with details on how to call the Scala script engine from plain Java, rather than from other Scala code. You made all my problems go away: scijava/scripting-scala@1950c73 🍻

@doriancransac
Copy link

Hi,

Using either one of the instructions, I'm getting the following error :

Exception in thread "main" java.lang.ClassCastException: scala.tools.nsc.interpreter.Scripted cannot be cast to scala.tools.nsc.interpreter.IMain
	at TestScala.main(TestScala.java:12)

Any idea why?

@ScalaWilliam
Copy link

@DCransac I'm having this problem too. Appears that there was a change in scripting engine between 2.11 and 2.12.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment