I'm about to start rewriting bits and pieces of our Rails app that do the relatively heavier number crunching in Scala for speed. The plan eventually is to have all the processing done by a scala daemon running in the background and just use Rails for the frontend, but in the meantime I want to be able to rewrite bits and pieces of the slower code now and call them synchronously from Ruby.
For this reason I've been looking at RJB (I can't use JRuby) in the hope that I can use it with scala too, seeing as it compiles to Java Bytecode in the end anyway. I've had a google around to see if I can find someone who's already done this or similar but not come up with anything.
My inital, naive attempt was to just compile and package a test scala class into a jar and try loading it using Rjb like this:
Rjb::load("#{Rails.root}/lib/scala/scala-tester-1.0-SNAPSHOT.jar")
MyClass = Rjb::import('com.mydomain.MyClass')
But this just results in a java.lang.NoClassDefFoundError: com/mydomain/MyClass
.
I tested importing a standard java class, which works fine, so I tested importing scala.Int
, which resulted in another NoClassDefFoundError
. This sort of suggests to me that the problem may lie in the scala libraries not being included on the classpath? But it's quite a while since I've had to deal with the endless headaches of Java classpaths so I'm pretty rusty at diagnosing and fixing this kind of problem.
So, has anyone done this? If not, does my hunch sound correct? Any suggestions? Or is there something I'm not thinking of that will mean this approach won't work at all?
EDIT: realised I'd been using slightly incorrect syntax. Have now managed to get it to load my test jar using syntax like this:
Rjb::load(classpath = "#{Rails.root}/lib/scala/scala-tester-1.0-SNAPSHOT.jar", jvmargs=[])
but fail with a different java.lang.NoClassDefFoundError: scala/ScalaObject
which suggests it definitely is failing to load the scala libraries.
I got it to work with the following:
RJB_LOAD_PATH = ["#{ENV['SCALA_HOME']}/lib/scala-library.jar", "#{Rails.root}/lib/scala/scala-tester-1.0-SNAPSHOT.jar"].join(File::PATH_SEPARATOR)
RJB_OPTIONS = []
Rjb::load(RJB_LOAD_PATH, RJB_OPTIONS)
Going to put this code in an initializer but it still seems a little hacky and would be glad to hear if anyone has any neater suggestions.