Как настроить classpath для интерпретатора Scala в управляемой среде? - PullRequest
6 голосов
/ 27 июля 2011

Я работаю над расширением для веб-платформы Apache Wicket, которая позволяет пользователю выполнять код на нескольких языках программирования во время выполнения из браузера.Одним из этих языков является Scala, но у меня возникают проблемы, когда он упакован в файл WAR и развернут в контейнере, таком как Tomcat.

Когда вызывается интерпретатор 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 он все равно не работает в управляемой среде.Похоже, проблема в том, что интерпретатор Scala не может найти jar-файлы библиотеки Scala на пути к классам Java.

При поиске в Интернете я нашел предложение , в котором предлагается использовать два ресурса classpath с именами «boot.class.path» и «app.class.path», которые должны включатьнужны объявления classpath.Я попробовал это, и это, казалось, сработало.Моя проблема с этим решением, тем не менее, заключается в том, что мое расширение предназначено для объединения в WAR-файл и его запуска в разных средах, поэтому пользователю необходимо изменить эти ресурсы в соответствии со средой, в которой он работает.Также было бы много работы, чтобы включить в файл путь к каждой банке.

Возможно, я не до конца понимаю предложение.Кто-нибудь знает решение для этого?

Ответы [ 3 ]

3 голосов
/ 29 февраля 2012

Мне удалось встроить 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)
2 голосов
/ 27 июля 2011

Вы можете попробовать создать и установить путь к классам вручную:

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

и передать этот экземпляр настроек компилятору Scala.

1 голос
/ 14 августа 2013

Я портировал на 2.10.2, и решение, предоставленное Питером, больше не работало.Я разгадал паутину, и все указали на решение, предложенное Скоттом, но оно также не сработало для меня.Я использую maven для копирования всех необходимых зависимостей в папку lib, которая включает библиотеку scala и компилятор.Maven также устанавливает (относительный) classpath для всех этих Jar-файлов в Манифесте.

Я уверен, что есть более элегантный способ сделать это - особенно доступ к нужному Манифесту прямо сейчас - и, возможно, есть некоторыеподводные камни, но у меня это работает:

    //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
...