Description
The JRuby adapter doesn't work because JRuby can't figure out which overloaded Observable#subscribe
method to pick. It ends up picking Observable#subscribe(Map<String, Object>)
, which raises an error because the argument doesn't respond right:
require 'rxjava-core-0.10.0.jar'
require 'rxjava-jruby-0.10.0.jar'
observable = Java::Rx::Observable.toObservable(['one', 'two', 'three'])
observable.take(2).subscribe(lambda { |x| puts x })
the code above prints the following errors in JRuby 1.7.4:
% ruby rxjava.rb
rxjava.rb:6 warning: ambiguous Java methods found, using subscribe(java.util.Map)
onNext
Observable.java:278:in `subscribe': java.lang.RuntimeException: 'onNext' key must contain an implementation
from NativeMethodAccessorImpl.java:-2:in `invoke0'
from NativeMethodAccessorImpl.java:57:in `invoke'
from DelegatingMethodAccessorImpl.java:43:in `invoke'
from Method.java:601:in `invoke'
from JavaMethod.java:455:in `invokeDirectWithExceptionHandling'
from JavaMethod.java:316:in `invokeDirect'
from InstanceMethodInvoker.java:61:in `call'
from MethodHandle.java:599:in `invokeWithArguments'
from InvocationLinker.java:153:in `invocationFallback'
from rxjava.rb:5:in `__file__'
from rxjava.rb:-1:in `load'
from Ruby.java:807:in `runScript'
from Ruby.java:800:in `runScript'
from Ruby.java:669:in `runNormally'
from Ruby.java:518:in `runFromMain'
from Main.java:390:in `doRunFromMain'
from Main.java:279:in `internalRun'
from Main.java:221:in `run'
from Main.java:201:in `main'
in JRuby 1.6.8 it prints a less verbose version of the same error.
Notice the line which reads "onNext". That's actually the puts
from lambda { |x| puts x }
in action. JRuby wraps the lambda in something that looks like a Map
, and then when RxJava calls get
on that map JRuby calls call
on the lambda.
So if you modify the example code to read lambda { |x| lambda { |y| puts y } }
this is what happens:
% ruby rxjava.rb
rxjava.rb:6 warning: ambiguous Java methods found, using subscribe(java.util.Map)
RxJava => Could not find function language adaptor: Groovy with path: rx.lang.groovy.GroovyAdaptor
RxJava => Successfully loaded function language adaptor: JRuby with path: rx.lang.jruby.JRubyAdaptor
RxJava => Could not find function language adaptor: Clojure with path: rx.lang.clojure.ClojureAdaptor
RxJava => Could not find function language adaptor: Scala with path: rx.lang.scala.ScalaAdaptor
one
two
Which kind of works, but it's not as smooth as the ideal API would be:
observable.subscribe { |x| puts x }
But that would probably require a real JRuby native extension (if I get the time I'll send you a pull request with one).