java interfaces

JRuby classes can mixin Java interfaces as modules in order to implement them.

class SomeFlexibleClass
  include java.lang.Runnable
  include java.lang.Comparable
end

JRuby does a wonderful thing with Ruby’s blocks, where a block can be converted to the appropriate Java interface. It works by converting the block to a Proc, and then decorating it with a proxy object that runs the block for any method called on the interface. Runnable is the prime example here. You should try this yourself, also see using callbacks hype library examples for more sophisticated stuff.

button = javax.swing.JButton.new "Press me!"
button.add_action_listener { |event| event.source.text = "I done been pressed." }

Read more about java interface etc. Otherwise see wiki

java reflection

In vanilla processing, you can create libraries in java that can access the sketch pre, draw, post, mouseEvent and keyEvent methods by java reflection, but you must register these methods with the PApplet. We can also register custom methods (but sadly only those without parameters, which is why we found another way of dealing with selectInput see chooser, movieEvent see video_event).

Here we show you how to registerMethods in a ruby class by java reflection in JRuby (requires the !become_java method).

# A simple demonstration of vanilla processing # 'reflection' methods
# in JRubyArt see register_send.rb for the guts...

require_relative 'register_send'

def settings
  size 300, 200
end

def setup
  sketch_title 'Reflection Voodoo'
  RegisterSend.new self
  no_loop
end

def draw
  fill(0, 0, 200)
  ellipse(170, 115, 70, 100)
end

Here is the class that does the reflection (it needs to become java so that self gets recognized as a java object)

require 'jruby/core_ext' # required to add become_java! method

# This class demonstrates how to use 'reflection' methods in ruby-processing
# NB: the class must become a java object to get registered. This is an
# advanced feature in vanilla processing, mainly used by libraries.
class RegisterSend
  attr_reader :parent

  def initialize(parent)
    @parent = parent
    parent.java_send :registerMethod, [java.lang.String, java.lang.Object], :draw, self
    parent.java_send :registerMethod, [java.lang.String, java.lang.Object], :pre, self
  end

  def pre
    puts 'before draw'
    parent.background(100)
  end

  def draw
    puts 'at begin draw...'
    parent.fill(200, 100)
    parent.ellipse(150, 100, 200, 60)
  end
  # putting become_java! here works OK
  become_java!
end

reflection voodoo

Note how the transparent ellipse is placed on top of the solid ellipse, so the reflection element must get drawn after the original sketch element.

Java Extensions for JRuby

JRuby is a 100% Java implementation of the Ruby programming language. It is Ruby for the JVM. So it is quite possible to write your own ruby code in java, you might do this to better integrate jruby with java or to write your own ruby classes (modules etc) in java see Method Signatures and Annotations in JRuby extensions and jruby-examples.

Accessing java methods with overloaded signatures

Sometimes you may find that a java method is not-available from ruby, and this can be because the java signature is overloaded. The preferred way to access such methods is to use java_alias. Using java_alias to create signature-specific aliases of a given method, avoids the lookup overhead and allows invokedynamic to optimize the calls. See example:-

# Here we re-open the SinOsc class to deal with java signatures
class SinOsc
  java_alias :just_play, :play
  java_alias :freq_float, :freq, [Java::float]
  java_alias :amp_float, :amp, [Java::float]
end

See full code listing here