Selecting Overloaded Java methods in JRuby

Posted March 4, 2013 by Sonny Garcia

JRuby, a Ruby language implementation that runs on the JVM, allows developers to leverage the vast number of powerful libraries that have been written in Java while maintaining the simplicity and terse nature of the Ruby programming language. Since Java allows for method overloading and Ruby does not, at some point we may find ourselves needing to choose which overload we want to invoke. Thankfully, JRuby provides us with a couple of mechanisms.

Before we actually discuss how to choose method overloads, we first need a little understanding about how Ruby objects can be casted into Java objects.

Auto-casting primitive Ruby types to Java

When calling Java code from Ruby, primitive Ruby types are automatically converted to their default boxed Java types. You can examine these default types by invoking #to_java on your Ruby objects.

  'orgsync'.to_java # => #<Java::JavaLang::String:0x3b8590c5>
  2013.to_java # => #<Java::JavaLang::Long:0x5ae6c6d7>
  3.14.to_java # => #<Java::JavaLang::Double:0x635c80a4>
  true.to_java # => #<Java::JavaLang::Boolean:0x32554189>

Explicit casting

You can also explicitly cast your Ruby objects into compatible Java types by passing an argument to the #to_java method.

  2013.to_java(:short) # => #<Java::JavaLang::Short:0x59046270>
  3.14.to_java(:float) # => #<Java::JavaLang::Float:0x670064a4>

Method signature ambiguity

When passing your Ruby objects to Java methods, JRuby will try its best to cast them into the most suitable type. Sometimes, this operation fails because a method’s overloads accept very similar argument types in relation to the provided object.

As an example, let’s examine the type org.apache.poi.hssf.usermodel.HSSFRow defined in Apache’s POI library. Instances of this class respond to the method createCell(); it accepts 1 argument and has 2 overloads, namely, HSSFRow#createCell(int) and HSSFRow#createCell(short).

Since, in our code, we would most likely pass this method a Ruby Fixnum like 123, JRuby will issue a warning in the console/logs indicating that it was unable to figure out the correct overload. This makes sense since our Fixnum will automatically cast into a java.lang.Long object, which is neither a java.lang.Integer nor a java.lang.Short. Which overload is best suited for the task?

Choosing the right overload (you make the choice!)

Strategy 1: Force execution of a named method

Using java_send you can specify which overload to use because it overrides JRuby’s dispatch rules and looks for a method with the input signature you provide.

  # The 1st arg is the "method name"
  # The 2nd arg is the "input call signature"
  # The last args are the actual "input values"

  hssf_row.java_send(:createCell, [java.lang.Integer], 123) # => a new cell object

NOTE: Since java_send relies on reflection, this strategy may yield poor performance.

Strategy 2: Grab the method you need

We can grab an unbound method off of our object using java_method and execute it directly. This provides us with a straightforward and efficient way to specify which overload we want to invoke.

  # We can choose our overload very similarly to how we invoke `java_send`

  unbound_method = hssf_row.java_method(:createCell, [java.lang.Intger]) # => a new cell object

Closing Thoughts

The strategies listed above will allow you to selectively invoke the desired version of a method on any Java objects you work with in your JRuby code. Please be aware that, while you can invoke methods on your objects using either camelcase or snakecase versions of method names (i.e. row.createCreate and row.create_cell are equivalent ), you must always use the camelcase version of a method name as a reference when using either java_send or java_method.

Sonny Garcia graduated from Texas State University with a B.S. degree in Physics and then shortly thereafter turned his attention towards software development and computing systems in general. Since 2007, he has been building backend systems, web applications and web service integrations for notable companies such as Dow Chemical and Equifax. These days he spends his time architecting and refining the server infrastructure here at OrgSync to ensure our platform runs smoothly, reliably and scales on demand. He's an odd bird, but we love working with him just the same.

comments powered by Disqus