如何使用Scala ScriptEngine调用函数或模块

时间:2018-03-16 11:13:32

标签: scala scriptengine

如何使用ScriptEngine调用函数或模块。

这是我的示例代码,编译正常,但在运行时它抛出异常scalaVersion:=“2.12.4”和sbt.version = 0.13.16,java是jdk1.8.0_131

import java.io.FileReader
import javax.script._

object DemoApp extends App {
    val engine: ScriptEngine with Compilable with javax.script.Invocable  = new ScriptEngineManager()
    .getEngineByName("scala")
    .asInstanceOf[ScriptEngine with javax.script.Invocable with Compilable]
    val reader = new FileReader("src/main/scala/Demo.sc")
    engine.compile(reader).eval()
    val result = engine.invokeFunction("fun")
}
下面的

是Demo.sc

def fun: String = {
"Rerutn from Fun"
}

以下是运行时的异常

Exception in thread "main" java.lang.ClassCastException: scala.tools.nsc.interpreter.Scripted cannot be cast to javax.script.Invocable
at DemoApp$.delayedEndpoint$DemoApp$1(DemoApp.scala:13)
at DemoApp$delayedInit$body.apply(DemoApp.scala:5)
at scala.Function0.apply$mcV$sp(Function0.scala:34)
at scala.Function0.apply$mcV$sp$(Function0.scala:34)
at scala.runtime.AbstractFunction0.apply$mcV$sp(AbstractFunction0.scala:12)
at scala.App.$anonfun$main$1$adapted(App.scala:76)
at scala.collection.immutable.List.foreach(List.scala:389)
at scala.App.main(App.scala:76)
at scala.App.main$(App.scala:74)
at DemoApp$.main(DemoApp.scala:5)
at DemoApp.main(DemoApp.scala)

2 个答案:

答案 0 :(得分:3)

我认为问题在于 Scala 脚本引擎实现Compilable,而不是Invocable,这就是您获得强制转换异常的原因。

在任何情况下,当您对编译结果致电eval时,您的代码都会被执行,因此您无需通过Invocable调用任何内容。

使用asInstanceOf有点皱眉,所以以下更具惯用性。

试试这个:

import java.io.FileReader
import javax.script._

object DemoApp extends App {
  // Get the Scala engine.
  val engine = new ScriptEngineManager().getEngineByName("scala")

  // See if the engine supports compilation.
  val compilerEngine = engine match {
    case c: Compilable => Some(c)
    case _ => None
  }

  // If the engine supports compilation, compile and run the program.
  val result = compilerEngine.map {ce =>
    val reader = new FileReader("src/main/scala/Demo.sc")
    ce.compile(reader).eval()
  }

  println(result.fold("Script not compilable")(_.toString))
}

或者,如果您只想让原始代码正常工作,那么您应该这样:

import java.io.FileReader
import javax.script._

object DemoApp extends App {
  val engine = new ScriptEngineManager()
    .getEngineByName("scala")
    .asInstanceOf[ScriptEngine with Compilable]
  val reader = new FileReader("src/main/scala/Demo.sc")
  val result = engine.compile(reader).eval()
  // Output the result
  println(result.toString)
}

答案 1 :(得分:0)

在脚本中使用actor的解决方法 -

主要应用程序演示

class SampleActor extends Actor {
    implicit val log = Logging(context.system, this)
    def fun() = {
        val settings: Settings = new Settings
        settings.sourcepath.value = "src/main/scripts"
        settings.usejavacp.value = true
        settings.dependencyfile.value = "*.scala"
        val engine: Scripted = Scripted(new Scripted.Factory, settings)
        engine.getContext.setAttribute("context0",context,ScriptContext.ENGINE_SCOPE)

        val reader = new FileReader("src/main/scripts/ActorScript.scala")
        engine.eval("import akka.actor.ActorContext \n" +"val context1 = context0.asInstanceOf[ActorContext]")

        val compiledScript : CompiledScript = engine.compile(reader)
        val x = compiledScript.eval()
        x.asInstanceOf[ActorRef] ! "Arikuti"
        x.asInstanceOf[ActorRef] !  1
    }
    override def receive: Receive = {
        case x : String =>
          log.info("Receveid  from ScriptEngine: " +  x)
        case i : Int =>
          log.info("Receveid from ScriptEngine : " +  i)
    }

    override def preStart(): Unit = {
        super.preStart()
        fun()
      }
    }

object ActorDemo {
  def main(args: Array[String]): Unit = {
  val system = ActorSystem("clientAdapter")
  val x = system.actorOf(Props(classOf[SampleActor]),"Main")
}
}

以下3个抄写员被放置在src / main / scripts

ActorScript.scala

import akka.actor.{Actor, ActorRef, Props}
import akka.event.Logging


class ActorScript extends Actor {
implicit val log = Logging(context.system, this)

override def receive = {
case y : Int   =>
  log.info("Recevied from Main Int : " +  y.toString )
  log.info(Convert.fun())
  sender.tell(2,self)
case x : String =>
  log.info("Recevied from Main String " + x)
  log.info(Second.fun())
  sender.tell("Arikuti",self)
}
}

object ActorScript {
  def apply: ActorRef = {
    context1.actorOf(Props(new ActorScript),"ScriptActor")
  }
}

ActorScript.apply

Convert.scala

object Convert {
  def fun(): String = {
    "I am from Converter:: fun"
  }
}

Second.scala

object Second {
  def fun(): String = {
    "I am from Second::fun"
  }
}

在build.sbt

excludeFilter in unmanagedSourceDirectories :=  "src/main/scripts/*.scala"

现在从应用程序我可以向已编译的脚本actor发送消息,并从Scripipts接收已处理的值