1 min read

JRuby Complex Classes in Java Method Signatures

As documented in the JRuby wiki, java_signature changes a method’s signature to match the signature string passed to it:

require 'jruby/core_ext'
class Foo
java_signature 'void bar(int, int)'
def bar(a, b)
puts a + b
end
end
Foo.become_java!.declared_methods.each { |m|
puts m
}
view raw example(1).rb hosted with ❤ by GitHub
Observe that the classes in the method signature are primitive. What if we use a complex class as a parameter type?

require 'jruby/core_ext'
class MyClass
attr_accessor :b
def initialize(b)
@b = b
end
end
class Foo
java_signature 'void bar(int, MyClass)'
def bar(a, my_class)
puts a + my_class.b
end
end
Foo.become_java!.declared_methods.each { |m|
puts m
}
view raw example(2).rb hosted with ❤ by GitHub
Running the above code will give you the following NoMethodError message:

NoMethodError: undefined method `start_with?' for #<Java::OrgJrubyAstJava_signature::ReferenceTypeNode:0x3b9fa8f7>
as_java_type at /opt/jruby-1.7.4/lib/ruby/shared/jruby/compiler/java_signature.rb:20
parameters at /opt/jruby-1.7.4/lib/ruby/shared/jruby/compiler/java_signature.rb:48
each at file:/opt/jruby-1.7.4/lib/jruby.jar!/jruby/java/java_ext/java.util.rb:7
map at org/jruby/RubyEnumerable.java:713
parameters at /opt/jruby-1.7.4/lib/ruby/shared/jruby/compiler/java_signature.rb:48
types at /opt/jruby-1.7.4/lib/ruby/shared/jruby/compiler/java_signature.rb:54
java_signature at /opt/jruby-1.7.4/lib/ruby/shared/jruby/core_ext/class.rb:44
Foo at lib/example.rb:12
(root) at lib/example.rb:11
view raw error hosted with ❤ by GitHub
The way I went about using complex classes in signatures is to utilise add_method_signature instead of java_signature:

require 'jruby/core_ext'
class MyClass
attr_accessor :b
def initialize(b)
@b = b
end
end
class Foo
add_method_signature('bar', [java.lang.Void, Java::java.lang.Integer::TYPE, MyClass.become_java!(false)])
def bar(a, my_class)
puts a + my_class.b
end
end
Foo.become_java!.declared_methods.each { |m|
puts m
}
view raw example(3).rb hosted with ❤ by GitHub
add_method_signature expects the first argument to be the name of the method that will have its signature changed. For the second argument, it expects it to be a list of classes. The list’s first item is the return class (e.g., void) while the subsequent items are the signature’s parameter classes (e.g., int and MyClass). Note that I invoke become_java! on the complex class. This tells MyClass to materialize itself into a Java class. The false flag is needed so that JRuby’s main class loader is used to load the class. Without it, you’ll be greeted by a java.lang.ClassNotFoundException.