2

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.

2 Answers 2

2

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

Sign up to request clarification or add additional context in comments.

3 Comments

When I put the Scala code as a string directly into apply, I does not print the result of the "main" method from the object. I am able to compile it via "eval.compile(scalaCode.toString());". However, from there I am unable to run it. If you want me to post my Scala code as part of the question, I can do so.
Why don't you just append the invocation? Like "object Foo extends App { println("hello") }" -> "object Foo { ... }; Foo.main(new Array[String](0)).
's approach is what I ended up using to call the function inside the object from my Java program.
1

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.