Search code examples
jruby

How do I implement specific interface methods using closure conversion in jruby?


I would like to take different actions when an swt menu is shown or hidden, so I am adding a MenuListener to a Menu

If I create the listener using a class and add an instance of that class via add_menu_listener I can separately detect showing events and hiding events. For example using the following Listener class:

  class MyListener
    include MenuListener

    def menu_shown e
      puts "#{e} was a show event"
    end

    def menu_hidden e
      puts "#{e} was a Hide event"
    end
  end

and then add the listener to the menu via

my_menu.add_menu_listener MyListener.new 

will print different messages when the menu is shown vs hidden.


I can also add a listener using "closure conversion" for example this will produce a message whenever the menu is shown or hidden.

my_menu.add_menu_listener { |e| puts "#{e} was a menu event" } 

These two sections of the jruby wiki seem to cover implementing interfaces in jruby.

https://github.com/jruby/jruby/wiki/CallingJavaFromJRuby#implementing-java-interfaces-in-jruby https://github.com/jruby/jruby/wiki/CallingJavaFromJRuby#closure-conversion

The second section seems to indicate that this "closure conversion" method should work for any interface, but I can't figure out out to get it to separate out the two different methods.


Does anyone know how to use this "closure conversion" scheme to implement each of the specific interface methods separately?


Solution

  • Looking more closely at https://github.com/jruby/jruby/wiki/CallingJavaFromJRuby#closure-conversion I see this statement:

    The block is converted to a Proc object, which is then decorated with a java interface proxy that invokes the block for any method called on the interface.

    I think this means there is no way to tell what method called the block.

    What I decided to (unless someone has a better solution) is this

    show = "Show"
    hide = "Hide"
    my_listener = MenuListener.new
    my_listener.define_singleton_method(:menu_shown) { |e| puts "#{e} was a #{show} event" }
    my_listener.define_singleton_method(:menu_hidden) { |e| puts "#{e} was a #{hide} event" }
    my_menu.add_menu_listener my_listener
    

    Note: I chose this over

    my_listener = MenuListener.new
    class << my_listener
       def menu_shown e
           ...
       end
       def menu_hidden e
           ...
       end
    end
    my_menu.add_menu_listener my_listener
    

    since I need to reference some free variables as shown above