2013-10-21 20 views
3

我想将我的java代码移植到纯斯卡拉,所以将不胜感激在这方面的任何帮助。斯卡拉运行时间代码编译

下面的代码首先将我的业务逻辑转换为java代码。在这里,我使用freemarker模板来执行基于模板的代码生成。创建文件后,我使用java comiler编译代码并创建一个jar文件,该文件保存在一个临时目录中

我目前使用提供运行时编译的javax.tools.*包。什么是斯卡拉等同于这种方法?我想用freemarker模板生成纯粹的Scala代码,然后运行Scala编译来创建一个jar文件。

下面是我用来实现此目的的示例Java代码。

JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); 
    Iterable<? extends JavaFileObject> compilationUnits = Arrays.asList(javaFileObjects); 
    StringBuilder builder = new StringBuilder(); 
    builder.append(service.getConfig().getProp("coreLib")); 
    builder.append(";" +result.getCodeContext().getOmClasspath()); 
    builder.append(";" +jarBuilder.toString()); 
    builder.append(";" +service.getConfig().getProp("tempCodeGen")); 
    String[] compileOptions = new String[]{"-d", result.getCodeContext().getOmClasspath(),"-cp",builder.toString()} ; 
    Iterable<String> compilationOptionss = Arrays.asList(compileOptions); 
    DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<JavaFileObject>(); 
    CompilationTask compilerTask = compiler.getTask(null, stdFileManager, diagnostics, compilationOptionss, null, compilationUnits) ; 
    boolean status = compilerTask.call(); 
+0

你有没有考虑使用宏? http://docs.scala-lang.org/overviews/macros/toc.html –

回答

3

下面是从我自己的代码一些方法来编译项目,并将其打包成一个罐子。它与抛光或正确评论相差甚远,但希望它能指出你需要开始的地方。我不认为你需要使用String Builder,因为这不是性能关键:

def buildAll(name: String, projDir: String, mainClass: String = ""): Unit = 
{ 
    import scala.tools.nsc.{Settings,Global} 
    val relSrc : List[String] = List() 
    val maniVersion = "None" 
    def targDir: String = projDir + "/targ" 
    def srcDir: String = projDir + "/src" 
    def srcDirs: List[String] = srcDir :: relSrc 

    import java.io._ 
    val sings = new scala.tools.nsc.Settings  
    new File(targDir).mkdir 
    sings.outputDirs.setSingleOutput(targDir.toString)  
    val comp = new Global(sings)  
    val crun: comp.Run = new comp.Run 
    def getList(fName: String): List[String] = 
    { 
    println("starting getList " + fName) 
    val file = new File(fName) 
    if (file.isDirectory) file.listFiles.toList.flatMap(i => getList(fName + "/" + i.getName)) 
    else List(fName) 
    } 

    crun.compile(srcDirs.flatMap(i => getList(i))) 
    import sys.process._ 
    ("cp -r /sdat/projects/ScalaLibs/scala " + targDir + "/scala").! 

    import java.util.jar._ 
    val manif = new Manifest 
    val mf = manif.getMainAttributes 
    mf.put(Attributes.Name.MANIFEST_VERSION, maniVersion) 
    if (mainClass != "") mf.put(Attributes.Name.MAIN_CLASS, mainClass) 
    val jarName = name + ".jar" 
    val jarOut: JarOutputStream = new JarOutputStream(new FileOutputStream(projDir + "/" + jarName), manif) 
    AddAllToJar(targDir, jarOut)  
    jarOut.close 
} 

def addToJar(jarOut: JarOutputStream, file: File, reldir: String): Unit = 
{ 
    val fName = reldir + file.getName   
    val fNameMod = if (file.isDirectory) fName + "/" else fName 
    val entry = new JarEntry(fNameMod) 
    entry.setTime(file.lastModified)   
    jarOut.putNextEntry(entry) 
    if (file.isDirectory) 
    { 
    jarOut.closeEntry 
    file.listFiles.foreach(i => addToJar(jarOut, i, fName + "/")) 
    } 
    else 
    {   
    var buf = new Array[Byte](1024) 
    val in = new FileInputStream(file) 
    Stream.continually(in.read(buf)).takeWhile(_ != -1).foreach(jarOut.write(buf, 0, _)) 
    in.close 
    jarOut.closeEntry() 
    }   
} 
def AddAllToJar(targDir: String, jarOut: JarOutputStream): Unit = 
    new java.io.File(targDir).listFiles.foreach(i => addToJar(jarOut, i, "")) 

您需要将Scala编译器添加到构建路径。 Scala编译器获取源文件的列表,并在输出目录中设置的目录中生成已编译的类文件。但掌握编译器的全部功能是一项重要任务。

0
+0

AFAIK,Eval不允许您*生成*代码,例如物理构建代码并将其捆绑为jar,所以它不是问题所在。不太确定第一个。 –

+0

当提供标准的“-d”选项时,工具箱会将代码转储到指定的目录中:https://github.com/scala/scala/blob/371bad2fe657d7fd065a47dc38fa5ae1fea882a7/src/compiler/scala/tools/reflect/ToolBoxFactory.scala #L322 –

1

而使用scala时,您不需要使用任何自由标记类似的工具。由于scala版本2.10有字符串插值功能。

val traitName = "MyTrait" 
val packageName = "my.pack" 
val typeParams = List("A", "B", "C") 

s""" 
    |package ${packageName} 
    | 
    |trait ${traitName}[${typeParams.mkString(",")}] { 
    | ${typeParams.map(t => s"val ${t.toLowerCase()}: ${t}")} 
    |} 
    | 
""".stripMargin 

将产生:

package my.pack 

trait MyTrait[A,B,C] { 
    List(val a: A, val b: B, val c: C) 
} 

无依赖性所需:)

+0

这是一个很好的方法,但是在我的情况下,模板内容存储在一个文件中,而字符串插值是一个编译时功能,所以从技术上讲,除非我错过了某些东西,否则无法实现。请参阅下面的代码\t val c2 = Source.fromFile(“C:/templates/datadomain.ftl”)。getLines.mkString datadomain.ftl的内容 - 包om。$ {data.id +“_”+ data.version} ; – GammaVega

+1

请注意,使用quasiquotes(http://docs.scala-lang.org/overviews/macros/quasiquotes.html)时,不再需要使用容易出错的字符串操作来组装Scala代码。 –

1

如果你想编译生成的代码在运行时,最简单的办法是twitter eval utility

+0

读者注意:twitter eval将被弃用,不应用于新代码。 –