JewelRuby

... bytes and babes of JRuby

An Obvious Java Dispatch

Features mentioned here are available since JRuby 9.0.1.0 and 1.7.22

JRuby’s “Java Integration”, behind the magical require 'java', has been a mesmerizing case ever since it was first introduced and stands as a reliable ground for a lot of very appealing libraries.

Although most the time it’s very intuitive (e.g. java.util.ArrayList.new(8)), sometimes the finest details behind the curtains need real world use-cases to get right. Mostly due the fact that in Ruby there’s always a single method to call given a name, while in Java method dispatch accounts for static parameter types. Add automatic Ruby to Java type conversion on top and things get ambiguous every so often as JRuby tries to match the right Java method for you.

One such case that needs special care is matching a “proc-to-interface” method when users implement an interface using a Ruby proc/block :

# listFiles( FileFilter#accept(File) )

java.io.File.new('.').listFiles do |pathname|
  pathname.file? && pathname.can_read
end

The intent is clearly listFiles( FileFilter ) as the java.io.FileFilter (functional) interface requires an accept(File pathname) that takes a single argument. But what if the block arity changes :

# listFiles( FilenameFilter#accept(File, String) )

java.io.File.new('.').listFiles do |dir, name|
  java.io.File.new(dir, name).can_read
end

Obviously, in this case the listFiles( FilenameFilter ) method is a better match since java.io.FilenameFilter prescribes a method with 2 parameters to be implemented.

Turns out Java method matching wasn’t 100% deterministic with ambiguous overloaded methods in general (not just those ending with a proc) and depended on JVM’s reflected method order, thus expect a lot of confusing “warnings” to be ironed out. It’s also why the change is not considered breaking for JRuby 1.7.