How can I force JRuby to initialize a java ArrayList with java Longs instead of Fixnums?

826 Views Asked by At

Someone on my team is writing a ruby/cucumber test that calls a java api that takes a List<Long> argument. I'm trying to help him out but my jruby knowledge is pretty limited. Whenever the call to the java method that takes List<Long> is made the java method is throwing some sort of class cast exception because the ArrayList contains all ruby Fixnum objects.

The following simplified code shows that I always get a Fixnum not a Java::JavaLang::Long

irb(main):017:0> java.util.ArrayList.new([12.to_java])[0].class
=> Fixnum

This is even though the following shows that 12.to_java produces a Long

irb(main):018:0> 12.class
=> Fixnum
irb(main):019:0> 12.to_java.class
=> Java::JavaLang::Long 

I've also tried not using the constructor args

irb(main):020:0> a = java.util.ArrayList.new
=> #<Java::JavaUtil::ArrayList:0x314e60d2>
irb(main):021:0> a.add(12.to_java)
=> true
irb(main):022:0> a[0].class
=> Fixnum

And gone as far a just instantiating a java.lang.Long directly

irb(main):023:0> a = java.util.ArrayList.new
=> #<Java::JavaUtil::ArrayList:0xfdcb343>
irb(main):024:0> a.add(java.lang.Long.new(12))
=> true
irb(main):025:0> a[0].class
=> Fixnum

And my last attempt

irb(main):026:0> b = 12.to_java
=> #<Java::JavaLang::Long:0x244ff48e>
irb(main):027:0> b.class
=> Java::JavaLang::Long
irb(main):028:0> a = java.util.ArrayList.new
=> #<Java::JavaUtil::ArrayList:0x6a36ebaa>
irb(main):029:0> a.add b
=> true
irb(main):030:0> a.get(0).class
=> Fixnum
1

There are 1 best solutions below

0
On BEST ANSWER

actually, this is far easier than you think and will work fine if you just pass a [] around :)

while on the Ruby side JRuby makes sure values are Ruby-like but when it reaches the Java end - in case of a RubyArray instance passed to Java (which actually implements java.util.List) - it will auto-convert "toJava" at it's best. means for Ruby Fixnums you will get java.lang.Long on operations such as java.util.List#get :

public class JavaAPI {
    public void testListArgument(final List<Long> list) {
        System.out.println("list = " + list + " list.class = " + list.getClass() + " list[0].class = " + list.get(0).getClass());
    }
}

compile this .java (under target/classes) than doing something like jruby -S irb :

jruby-1.7.16 :007 > $CLASSPATH << 'target/classes'
 => ["file:/opt/local/rvm/rubies/jruby-1.7.16/lib/ruby/shared/readline/jline-2.11.jar", "file:/opt/local/rvm/rubies/jruby-1.7.16/lib/ruby/shared/readline/readline.jar", "file:target/classes/"] 
jruby-1.7.16 :009 > Java::JavaAPI.new.testListArgument [1]
list = [1] list.class = class org.jruby.RubyArray list[0].class = class java.lang.Long
 => nil