Java integration: Can we create a scala engine with the JSR-223 API from inside an Eclipse plugin?

I am using scala-2.12.3-1.noarch RPM on Fedora 25 with java 1.8, eclipse 4.6.3 for plugin development. My intent is to write an Eclipse Rich Client Product that will let users choose their scripting languages for writing quick and dirty interactive requests. I can create scala engines as well as javascript (nashorn) and scheme engines when the code is run as a simple java application (without any plugin mechanism). However, when the code is run as an Eclipse plugin, although I can still get a ScriptEngineFactory for scala from the ScriptEngineManager, the ScriptEngineManager will return null when the method GetEngineByName is called. I do not have this problem when creating Javascript and Scheme engines from a plugin. When trying to create a scala engine from a plugin, the method is certainly doing something as it takes almost the same time (3-4s) when called from a simple Java application.
Besides the classpath, do you have to set some special environment to create a scala engine from inside a plugin ?

Hello again,
I have managed to get a stack trace by using the method GetScriptEngine on a ScriptEngineFactory, an alternative method.

(Arsene:19169): Gtk-WARNING **: Negative content width -6 (allocation 1, extents 4x3) while allocating gadget (node toolbar, owner GtkToolbar)

(Arsene:19169): Gtk-WARNING **: Negative content width -6 (allocation 1, extents 4x3) while allocating gadget (node toolbar, owner GtkToolbar)
python : compilable and invocable
ECMAScript : compilable and invocable
XQuery : compilable and not invocable
Scheme : compilable and not invocable
java.lang.NullPointerException
language [scala] cannot be started.
at scala.tools.nsc.interpreter.Scripted$$anon$2$$anon$1.error(Scripted.scala:68)
at scala.reflect.internal.Reporting.globalError(Reporting.scala:69)
at scala.reflect.internal.Reporting.globalError$(Reporting.scala:69)
at scala.reflect.internal.SymbolTable.globalError(SymbolTable.scala:16)
at scala.reflect.internal.Reporting.globalError(Reporting.scala:55)
at scala.reflect.internal.Reporting.globalError$(Reporting.scala:55)
at scala.reflect.internal.SymbolTable.globalError(SymbolTable.scala:16)
at scala.tools.nsc.symtab.SymbolLoaders.signalError(SymbolLoaders.scala:51)
at scala.tools.nsc.symtab.SymbolLoaders$SymbolLoader.complete(SymbolLoaders.scala:228)
at scala.reflect.internal.Symbols$Symbol.info(Symbols.scala:1531)
at scala.reflect.internal.Symbols$Symbol.initialize(Symbols.scala:1679)
at scala.reflect.internal.Definitions$DefinitionsClass.init(Definitions.scala:1448)
at scala.tools.nsc.Global$Run.(Global.scala:1154)
at scala.tools.nsc.interpreter.IMain._initialize(IMain.scala:125)
at scala.tools.nsc.interpreter.IMain.initializeSynchronous(IMain.scala:147)
at scala.tools.nsc.interpreter.Scripted.(Scripted.scala:74)
at scala.tools.nsc.interpreter.Scripted$.apply(Scripted.scala:309)
at scala.tools.nsc.interpreter.Scripted$Factory.getScriptEngine(Scripted.scala:302)
at arsene.script.Script_Manager.get_engine(Script_Manager.java:88)
at arsene.filter.expression.Dialog_Tree$5.handleEvent(Dialog_Tree.java:389)

Apparently, the scala engine factory has detected an error and is reporting it.

Bit of a guess because the stack trace is a little odd in that a line’s
been inserted after the NullPointerException but perhaps there’s a null
pointer in the error reporter
https://github.com/scala/scala/blob/v2.12.3/src/repl/scala/tools/nsc/interpreter/Scripted.scala#L68
masking
this a bit?

It looks like the actual error originated here:

scala.tools.nsc.symtab.SymbolLoaders$SymbolLoader.complete(
SymbolLoaders.scala:228)
https://github.com/scala/scala/blob/v2.12.3/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala#L228

If that’s a MissingRequirementError then there’s likely something missing
or different about the classpath when you run this as an eclipse plugin.
Perhaps one of the scala jars is missing?

Brian

Hello, Brian,

Yes, the scala jars are seen all missing because I suspect that Eclipse plugins are not using regular class loaders. The plugin contains certainly all the jars but probably they are not accessible by a standard java class path. I suppose they must be accessed relatively to the plugin rather than the root of the filesystem.

You might want to ask the Scala IDE folks.

can you try getEngineByExtension("scala")

scala -cp ~/.coursier/cache/v1/https/repo1.maven.org/maven2/org/scala-lang/scala-compiler/2.12.2/scala-compiler-2.12.2.jar 
Welcome to Scala 2.12.2 (OpenJDK 64-Bit Server VM, Java 1.8.0_131).
Type in expressions for evaluation. Or try :help.

scala> import javax.script._
import javax.script._

scala> val engines = new ScriptEngineManager().getEngineByExtension("scala")
engines: javax.script.ScriptEngine = scala.tools.nsc.interpreter.Scripted@591e5fd4

scala> engines.eval("1+1")
res0: Object = 2

I made some progress on my side. I have seen in an example that a ScriptEngine can be cast in an IMain. Then an IMain can be created with a Settings. Then a Settings allows among other things to define the class path. So I have been able to create from the plugin an IMain with the appropriate class path and give it something to execute. I am close. But I still cannot create a ScriptEngine. Is there a way to tell to the ScriptEngineFactory to use a Settings ?

Bonjour Guillaume,

On my installation, creating a scala engine from scala works by any methods I have tried. And it fails by any methods i have tried when creating from within an Eclipse plugin.

Try the following:

import scala.tools.nsc._
import interpreter._
trait Probe
val settings = new Settings
settings.embeddedDefaults[Probe] // this should set the correct classpath
val engine = Scripted(new Scripted.Factory, settings)
engine.eval("1+1")

I translate it in java. It works when I hard-code the class path. I could not get it working using the embeddedDefaults method using either Thread.currentThread ().getContextClassLoader() or Object.class.getClassLoader()

Thanks for your help.

I was just looking at https://github.com/scala/bug/issues/8669 because I think MasseGuillaume posted an issue. I was going to try pushing the embeddedDefaults trick into Scripted.apply, but I haven’t followed up yet.