-
The Call of ChrismathuluR.J. LorimerFri, Nov 7 2008 @ 2:38 pm
-
Getting True Java Classes in JRubyR.J. LorimerThu, Sep 25 2008 @ 6:41 pm
-
JRuby 1.1.4 ReleasedR.J. LorimerFri, Aug 29 2008 @ 5:41 am
-
My XBoxR.J. LorimerMon, Aug 25 2008 @ 3:22 am
-
Why So Serious?R.J. LorimerSat, Aug 23 2008 @ 5:25 am
JRuby and Java Arrays
Recently, I’ve been toying with JRuby, and for the most part, I’ve been very pleased with the experience.
In the standard 1.0 JRuby release, most things work surprisingly well. As with any young product, there are always dark spots in the margins, but for the most part the roughest edges are in the Java-to-Ruby integration; something which should be expected to be an evolution for JRuby anyway. Even given that, once you get into the groove of using Ruby syntax and Java objects together, you know what works, what might not work so well, and you can really be quite productive.
One such ‘hurdle’ that I had to overcome was getting from a Ruby array into a Java typed array. JRuby handles coercion most Java types quite well (Ruby strings to Java strings, numbers to numbers, booleans to booleans, and nil to null). Arrays, unfortunately, are not quite as seamless. I also found the documentation on this subject lacking. In any case, let’s look at an example - consider this Java object:
public class SomeObject { private int[] numbers;
public int[] getNumbers() {
return numbers;
}
public void setNumbers(int[] numbers) {
this.numbers = numbers;
}
}
Now, ignoring the fact that, if you’re using JRuby you would probably be better served implementing this in Ruby to begin with, let’s focus on the integration aspect; in other words, this class already exists in Java, and you have to work with it. If you wanted to set the numbers on this object, a logical approach with JRuby would be to do this:
SomeObject = Java::mypackage.SomeObject object = SomeObject.new object.numbers = [1,2,3]
If you do, however, buried deep in one of the exceptions you get will be this error message:
TypeError:
expected [[I];
got: [org.jruby.RubyArray];
error: argument type mismatch
I have moved that on to multiple lines for clarity. In plain English, that’s saying that the method expected an int[], but instead received a RubyArray object. In other words, JRuby didn’t automatically coerce the RubyArray object into an int[] for us. This is something we have to help JRuby with, given our knowledge of the Java object we’re working with. To do this, you have to use the RubyArray method extension to_java, which takes a symbol representing the array type you need:
SomeObject = Java::mypackage.SomeObject object = SomeObject.new object.numbers = [1,2,3].to_java(:int)
Now, what if your object expected a Class type as opposed to a primitive; perhaps one of your own objects or a complex Java type? In that case, you simply pass in the constant you declared for that type. Here is a concrete example. Once again, here is the Java object:
public StringBuilder[] getBuilders() {
return builders;
}
public void setBuilders(StringBuilder[] builders) {
this.builders = builders;
}
}
As you see, this time it takes an array of java.lang.StringBuilder objects. Here is a block of Ruby code illustrating how you can set these on this object:
SomeObject = Java::mypackage.SomeObject StringBuilder = java.lang.StringBuilder object = SomeObject.new builders = [StringBuilder.new, StringBuilder.new, StringBuilder.new] object.builders = builders.to_java(StringBuilder)

Comments
What if you need an array of
What if you need an array of interfaces?
[].to_java(java.util.List)
This generates a Java array of java.lang.Object which fails.
Any workaround for this?
Very helpful post. Thanks.
Very helpful post. Thanks.