I am currently working on a project using Scala and Play Framework 2. I want to compile some Scala code during runtime and get the result from the interpreter. I found some examples on the internet and finally came up with the following code:
package controllers
import play.api.mvc.{Action, Controller}
import javax.script.ScriptEngineManager
class Interpreter extends Controller {
val interpreter = new ScriptEngineManager().getEngineByName("scala")
val settings = interpreter.asInstanceOf[scala.tools.nsc.interpreter.IMain].settings
settings.embeddedDefaults[Interpreter]
settings.usejavacp.value = true
def index = Action {
Ok(views.html.interpreter())
}
def interpret(input: String) = Action {
implicit request => interpreter.eval("1 to 10 foreach println")
Ok("Got: " + input)
}
}
object Interpreter
My problem is that I always get an error from scala.reflect.internal.FatalError: "package scala does not have a member Int"
, when trying to run this code. After some research I found similar problems described in this posts:
Scala and Play 2.0 Plugins Update 0.38.437 is Out
Scala compiler error: package api does not have a member materializeWeakTypeTag
My current Scala version is 2.11.4, so I tried to switch to a different "scala-compiler" and "scala-library" versions in my "build.sbt" file, but with no success. Like it was mentioned in the posts above it is probably a bug in Scala. I wondered if somebody has a solution or perhaps any workaround for the described problem.
Thanks in advance for any help or advice.
The issue is in classpath in projects using Scala and Play Framework 2. It can be resolved by populating classpath from SBT to the application:
Add to build.sbt file:
val sbtcp = taskKey[Unit]("sbt-classpath")
sbtcp := {
val files: Seq[File] = (fullClasspath in Compile).value.files
val sbtClasspath : String = files.map(x => x.getAbsolutePath).mkString(":")
println("Set SBT classpath to 'sbt-classpath' environment variable")
System.setProperty("sbt-classpath", sbtClasspath)
}
compile <<= (compile in Compile).dependsOn(sbtcp)
Code:
package controllers
import play.api.mvc.{Action, Controller}
import javax.script.ScriptEngineManager
class Interpreter extends Controller {
val interpreter = new ScriptEngineManager().getEngineByName("scala")
val settings = interpreter.asInstanceOf[scala.tools.nsc.interpreter.IMain].settings
//settings.embeddedDefaults[Interpreter] // not need
//settings.usejavacp.value = true // not need
val sbtClasspath = System.getProperty("sbt-classpath")
settings.classpath.value = s".:${sbtClasspath}" // <-- this line fix the problem
def index = Action {
Ok(views.html.interpreter())
}
def interpret(input: String) = Action {
implicit request => interpreter.eval("1 to 10 foreach println")
Ok("Got: " + input)
}
}
object Interpreter
In production should be used another scenario to get a correct classpath.
Probably using a '-cp' or '-classpath' key from the command line.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With