Как я могу заставить JRuby инициализировать Java-массив ArrayList с помощью Java Longs вместо Fixnums?

Кто-то в моей команде пишет тест ruby ​​/cucumber, который вызывает Java-API, который требует List<Long> аргумент. Я пытаюсь помочь ему, но мои познания в области юрби довольно ограничены. Всякий раз, когда вызов метода Java, который принимает List<Long> сделано, что Java-метод генерирует какое-то исключение приведения класса, потому что ArrayList содержит все ruby Fixnum объекты.

Следующий упрощенный код показывает, что я всегда получаю Fixnum, а не Java::JavaLang::Long

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

Это даже при том, что следующее показывает, что 12.to_java производит Long

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

Я также пытался не использовать аргументы конструктора

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

И зашел так далеко, просто создание экземпляра java.lang.Long напрямую

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

И моя последняя попытка

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 ответ

Решение

На самом деле, это гораздо проще, чем вы думаете, и будет работать нормально, если вы просто сдадите [] вокруг:)

в то время как на стороне Ruby JRuby гарантирует, что значения подобны Ruby, но когда он достигает конца Java - в случае экземпляра RubyArray, переданного в Java (который фактически реализует java.util.List) - он будет автоматически конвертировать "toJava" в лучшем виде. средства для Ruby Fixnums вы получите java.lang.Long на такие операции, как 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());
    }
}

скомпилируйте этот.java (под target/ классы), чем делать нечто вроде 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 
Другие вопросы по тегам