Spring brings in the Money Google Developer Podcast: First Episode on Guice
May 14

Hiding your Ruby behind Java interfaces

Java, Ruby, Tech Add comments

I often get side tracked seeing JRuby as just a cure for Rails deployment issues. Although it is huge to think of a fast Ruby container, and having access to JVM internals for management and such, JRuby also has a fantastic set of Java integration features.

This means that while you are in Java-land, you can actually hide Ruby implementations of features behind nice Java interfaces. Rob Harrop showed off some of this at his JRuby DSL talk at JavaOne last Friday.

Here is a simple example of having Java code doing some kind of calculation, and behind the scenes the implementation is in Ruby.

The pieces are:

  • Java client code that does the calculation
  • Factory to return the object that can do the calculation
  • Calculation interface
  • The Ruby object that does the work
  • The Ruby file that makes the object implement the interface

Java Client Code

Calculator c = CalculatorFactory.getCalculator();
String calculation = "1 + 3";
System.out.println("Calculate(" + calculation + ") = " +  c.calculate(calculation));

Calculation interface

public interface Calculator {
public String calculate(String calculation);
}

Calculator Factory

The factory loads up the Ruby code, and then munges the Ruby object to return it back to Java-land as the Calculator interface:

public static Calculator getCalculator() {
Ruby runtime = Ruby.getDefaultInstance();

try {
runtime.evalScript(getContents("rcalculator.rb"));
runtime.evalScript(getContents("makejcalculator.rb"));
} catch (Exception e) {
System.err.println(e.toString());
e.printStackTrace();
}

Object c = runtime.evalScript("RCalculator.new");
c = JavaEmbedUtils.rubyToJava(runtime, (IRubyObject) c, Calculator.class);
return (Calculator) c;
}

The magic is done in JavaEmbedUtils.rubyToJava(runtime, (IRubyObject) c, Calculator.class);.

Ruby implementation of Calculator

The Ruby implementation is simple:

class RCalculator
def calculate(s)
return eval(s).to_s
end
end

To make it implement Calculator we monkey patch it by also loading the makejcalculator.rb file:

require 'java'

class RCalculator
include Java::Calculator
end

You could obviously do this all at once, but this pattern can allow you to share the Ruby code, and you may have other Ruby that you can’t just hack on.

This pattern will be common, so having a java_implement RCalculator, Java::Calculator simple piece of meta-code is useful.

All in all, JRuby gives you everything you need to do as much of your business logic in Ruby, and never expose it. This gives me thoughts of working on a Java team and telling my team mates about the interfaces they can use, and writing the entire app in Ruby behind the scenes ;)

6 Responses to “Hiding your Ruby behind Java interfaces”

  1. Anthony Eden Says:

    I’ve been down this path before and I can tell you that context switching between languages can be very, very painful. Perhaps it doesn’t seem that bad to you but consider that other developers may have a tougher go at it. I used to build webapps with JPublish where the actions were all implemented in Python. Eventually I got to the point where I just switched everything to Beanshell because it gave me the benefit of a scripting language while at the same time providing a much easier path to convert code to Java when performance was critical.

    Just a thought. Personally I don’t see Ruby deployment issues as such a big deal, so I can’t see myself using JRuby unless there was a library in Java that I absolutely *had* to have.

  2. Guillaume Laforge Says:

    It would be really magic if the so-called magic line wasn’t needed. On the contrary, here, it shows that Ruby and Java are just bridged and not really integrated nor share the same object models.

  3. glud Says:

    Craig Habuma blogged injecting Ruby (or Groovy) implementations of interfaces with Spring, in case you find yourself infiltrating a java team that also uses Spring.

    http://www.jroller.com/page/habuma?entry=spring_meet_ruby

  4. Ola Bini Says:

    Guillaume: Of course, we are bridging object systems. That’s the whole point of JRuby. If Ruby’s object system was the same as Java’s, we wouldn’t need JRuby at all. (blocks, closures, argument passing, method invocation, constant handling, module mixins are all parts of the object system, of course).

    That said, if Dion had used BSF or JSR223 to do the invocation, those parts wouldn’t have been visible.

  5. Florin T.PATRASCU Says:

    In my case, still using JPublish ;) (http://code.google.com/p/jpublish/) and using Rails in the same time, having JRuby available for writing JPublish Actions for web development (http://weblog.flop.ca/2007/07/17/1184705235053.html) is a very nice feature. I respect Anthony’s opinion and I would do the same and remain happy in the world of Ruby, but there are situations when you simply have to use a java library because is part of a legacy system that you have to maintain (even though I requested the permission to rewrite that system in Ruby ;) Having JRuby, allows constrained Java developers to taste the sweetness of Ruby … so I am one highly appreciating the existence of JRuby.

  6. replicahandbags Says:

    thanks for sharing,really enjoy reading your blog

Leave a Reply

Spam is a pain, I am sorry to have to do this to you, but can you answer the question below?

Q: Type in the word 'cricket'