Friday, May 29, 2009

Tips of embedding ruby gem in Java

I spent 2 weeks on embedding a ruby workflow engine ruote in Java by JRuby (will publish it later).
The followings are tips I got:
  • The JRuby wiki page Getting Started (http://wiki.jruby.org/wiki/Getting_Started) is out of date. Read http://wiki.jruby.org/wiki/Direct_JRuby_Embedding instead.
  • Should not use JavaUtil.* to convert java/ruby objects, which doesn't work well; use JavaEmbedUtils instead. And you probably should read javadoc of JavaEmbedUtils.
  • JavaEmbedUtils#invokeMethod accepts Java objects as arguments to call a method of ruby object so that you don't have to convert every Java objects to JRuby objects.
  • Create adapter for ruby object and wrap the ruby object with pure Java interface. So that no more JRuby interface need to care about outside.
  • Here is a JRuby IRubyObject adapter, which could get embedding easier.
  • A org.jruby.Ruby object looks like is thread safe, no matter calling evalScriptlet / callMethod. Wrote a test for it and worked well in my case.
  • Call JavaEmbedUtils#terminate to tear down a ruby runtime object and release resources, which is important in tests, otherwise you probably get out-of memory error.
  • Be careful to use YAML to dump a ruby object to string and convert the string to Java String, then load it back later. It didn't work well in my case when there is non-string ruby object attribute inside the ruby object dumped. In my case, the object attribute inside was load as string object when load the dumped string. And I failed to write a simple case to reproduce the problem. Marshal works well for me. (I use JRuby 1.3.0RC2 in my case)
  • You can package ruby gem's lib directory with your Java code as jar file to publish it. (same with jruby complete jar)
  • When package ruby code inside jar file, should be careful with using 'File.dirname(__FILE__)' to locate file location, which may doesn't work anymore (The "File.dirname(__FILE__)" will be looked like "...xx/xxx.jar!yyyy/zzzz").
  • If you are depending on another JRuby gem (e.g. ActiveRecord-jdbc-adapter) which includes a jar file in lib, you should package with the class files instead of the jar file, or put the jar file separated with your jar file. Java could not load a jar inside a jar file.