Reputation: 679
I am working on a Java program that takes a Scala program in a text file, compiles it (inside Java), then runs it (also inside Java). I could not figure out a clean way to implement this. To compile, I tried to use code as shown below:
import scala.collection.JavaConversions;
import scala.tools.nsc.Global;
import scala.tools.nsc.Settings;
Global g = new Global(new Settings());
Global.Run run = g.new Run();
List<String> fileNames = new ArrayList<String>(Arrays.asList("Hello.scala"));
run.compile(JavaConversions.asScalaBuffer(fileNames).toList());
However, I get an error (reduced for clarity):
error: error while loading Object, Missing dependency 'object scala in compiler mirror', required by C:\Program Files\Java\jdk1.7.0_79\jre\lib\rt.jar(java/lang/Object.class)
I did not understand what was causing this or how to fix. As a temporary workaround, I tried compiling the Scala code externally and calling that in Java via:
Runtime rt = Runtime.getRuntime();
Process pr = rt.exec("java -cp scala-library.jar;. Hello");
While I think the code runs, it is not interactive with the Java program as I would like. For example, when running the Scala program (inside Java) if the Scala program wanted the user to type a string into the console, the Java program should do the same essentially.
Any guidance is appreciated.
Upvotes: 2
Views: 1675
Reputation: 11
Looks like twitter eval is no more supported. Following https://github.com/open-src-code/btlang/blob/main/README.md supports what you are looking for
Example scala function to be executed from java
() => {
scala.io.Source.fromFile("src/test/resources/para.txt")
.getLines
.flatMap(_.split("\\W+"))
.foldLeft(Map.empty[String, Int]){
(count, word) => count + (word -> (count.getOrElse(word, 0) + 1))
}
}
Java code to execute the above function
String lambdaFunction = getSource("LambdaWordCountWithMap.scala"); // Lambda source
scala.collection.immutable.HashMap map = lambdaRunner.executeLambda(lambdaFunction, scala.collection.immutable.HashMap.class);
Assert.assertTrue(map.size() == 55);
disclaimer : I'm one of the author of this library.
Upvotes: 1
Reputation: 67280
The easiest way is probably just to use a tiny wrapper library that takes care of things like class-paths etc. For example, there is a small library Twitter Util-Eval (source).
Here is an example:
package foo;
import com.twitter.util.Eval;
public class Test {
public static void main(String[] args) {
final Eval eval = new Eval();
final int result = eval.apply("3 + 4", true);
System.out.println("Result: " + result);
}
}
If you want to bake your own compiler and runner wrapper, this involves a bit more, you will need to compile to virtual files and then load them into a class loader (see for example here and here).
Upvotes: 2