2011-07-27 59 views
6

我正在致力於Apache Wicket Web框架的extension,該框架允許用戶在運行時從瀏覽器以幾種編程語言執行代碼。其中一種語言是Scala,但當它作爲WAR文件捆綁並部署到Tomcat等容器時遇到問題。如何在託管環境中爲Scala解釋器設置類路徑?

當調用Scala的解釋,它拒絕與以下消息運行代碼:

Failed to initialize compiler: object scala 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 programatically, settings.usejavacp.value = true. 

建立在斯卡拉設置usejavacp後,它仍然沒有在託管環境中工作。問題似乎是Scala解釋器無法在Java類路徑中找到Scala庫jar。

在網上搜索,我找到了一個proposal,它建議使用兩個名爲'boot.class.path'和'app.class.path'的類路徑資源,它應該包含所需的類路徑聲明。我試過了,它似乎工作。但是,這個解決方案的問題在於,我的擴展是打算捆綁到一個WAR文件中,並在不同的環境中運行,所以用戶需要根據所運行的環境修改這些資源。將每個jar的路徑包含到文件中也是很多工作。

也許我不完全理解這個提議。有沒有人知道這個解決方案?

回答

2

您可以嘗試手動構建和設置類路徑:

val setting = new scala.tools.nsc.settings.MutableSettings(println(_)) 
settings.classpath.append("my/path") 

,並通過此設置實例的Scala編譯器。

+0

這可能意味着爲每個特定環境手動設置類路徑,對嗎?有什麼辦法可以避免這種情況? – cretzel

3

我設法將scala 2.9.1嵌入到在tomcat中運行的戰爭中。

這就是我做到的。

val code = """println("Hi");"""; 

val settings = new Settings 
val compilerPath = java.lang.Class.forName("scala.tools.nsc.Interpreter").getProtectionDomain.getCodeSource.getLocation 
val libPath = java.lang.Class.forName("scala.Some").getProtectionDomain.getCodeSource.getLocation 

println("compilerPath=" + compilerPath); 
println("settings.bootclasspath.value=" + settings.bootclasspath.value); 

settings.bootclasspath.value = List(settings.bootclasspath.value, compilerPath, libPath) mkString java.io.File.pathSeparator  
settings.usejavacp.value = true 
val interpreter = new IMain(settings) 

interpreter.interpret(code); 

只爲搜索引擎。這些是我的例外之前它的工作。

Failed to initialize compiler: object scala 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 programatically, settings.usejavacp.value = true. 

Exception in thread "Thread-26" java.lang.Error: typeConstructor inapplicable for <none> 
      at scala.tools.nsc.symtab.SymbolTable.abort(SymbolTable.scala:34) 
      at scala.tools.nsc.symtab.Symbols$Symbol.typeConstructor(Symbols.scala:877) 
      at scala.tools.nsc.symtab.Definitions$definitions$.scala$tools$nsc$symtab$Definitions$definitions$$booltype(Definitions.scala:157) 
      at scala.tools.nsc.symtab.Definitions$definitions$.init(Definitions.scala:814) 
      at scala.tools.nsc.Global$Run.<init>(Global.scala:697) 
      at scala.tools.nsc.interpreter.IMain.scala$tools$nsc$interpreter$IMain$$_initialize(IMain.scala:114) 
      at scala.tools.nsc.interpreter.IMain$$anonfun$initialize$1.apply$mcZ$sp(IMain.scala:127) 
      at scala.tools.nsc.interpreter.IMain$$anonfun$initialize$2.apply(IMain.scala:126) 
      at scala.tools.nsc.interpreter.IMain$$anonfun$initialize$2.apply(IMain.scala:126) 
      at scala.concurrent.ThreadRunner$$anon$2$$anonfun$run$2.apply(ThreadRunner.scala:45) 
      at scala.concurrent.ThreadRunner.scala$concurrent$ThreadRunner$$tryCatch(ThreadRunner.scala:31) 
      at scala.concurrent.ThreadRunner$$anon$2.run(ThreadRunner.scala:45) 
      at java.lang.Thread.run(Thread.java:662) 
+1

這幾天有一個簡單的捷徑,c.f.位於https://github.com/harrah/xsbt/wiki/FAQ底部的部分。 –

+0

@ScottMorrison現在鏈接已經死了 – lolski

1

我移植到2.10.2和彼得提供的解決方案沒有工作了。我將網絡分層,每個人都指出了斯科特提出的解決方案 - 但它對我來說也不起作用。我正在使用maven將所有需要的依賴項複製到lib文件夾,其中包括scala庫和編譯器。 Maven還爲Manifest中的所有Jars設置了(相對)類路徑。

我敢肯定有這樣做的更優雅的方式 - 尤其是訪問權清單馬上 - ,並且有可能是一些缺陷,但它爲我工作:

//Get Jarpath 
    val jarfile = this.getClass.getProtectionDomain.getCodeSource.getLocation.getPath 
    val jarpath = jarfile.take(jarfile.lastIndexOf("/") + 1) 

    //Get classpath from Manifest 
    val resources = getClass.getClassLoader.getResources("META-INF/MANIFEST.MF"); 
    val cpath = Buffer[String]() 

    //Get classpath from Manifest 
    while (resources.hasMoreElements()){ 
     val manifest = new Manifest(resources.nextElement().openStream()); 
     val attr = manifest.getMainAttributes.getValue("Class-Path") 
     //Convert to absolut paths 
     if (attr != null) {    
      cpath ++= attr.split(" ").map(p => {"file:" + {if(p(1) == '/') "" else jarpath} + p }) 
     } 
    } 


    val settings = new Settings 
    settings.bootclasspath.value = cpath.mkString(java.io.File.pathSeparator) 
    settings.usejavacp.value = true 
相關問題