Skip to content

Better Utilizing JRuby in Project Scripting

21
Aug
2007

Often times in a large-scale Java project, I find myself in need of performing small, discrete tasks with the existing project infrastructure.   The standard way of doing this has always been to add a main(String[]) method to a class or to add a separate driver class to perform the one operation.  This is a bit messy though, since it requires polluting your nice clean project with random utility classes.  A better way to do this would be if we could have a set of separate scripts which just perform the actions we need.  After all, that’s what scripting languages are best at, right?  Enter JRuby.

JRuby is really designed for this sort of thing.  Interoperating with Java is second nature to it, and easily performing small, discrete tasks is a perfect use for Ruby’s compact and intuitive syntax.  The one problem is JRuby makes it pretty hard to get at a project’s class library.

For example, I have a medium-sized web application project based on Wicket and ActiveObjects.  This project has not only its own sources (and hence compiled binaries) as part of its classpath, but it also relies heavily upon almost two dozen other JARs (contained within the WebContent/WEB-INF/lib directory).  Any sort of utility scripting would have to somehow gain access to all of these classes, otherwise its capabilities would be extremely limited.

Now the task I need to perform with this scripting (at least, the task which precipitated this effort) is to optimize the Lucene search index.  This index is managed through ActiveObject’s automagical indexing of entity values.  The problem is that the index will grow rather organically, eventually becoming extremely slow.  I can’t just cause the application to stop at some arbitrary point and optimize the index since that would mean blocking a page load somewhere along the line.  As such, this is a perfect candidate for an external utility script.

Examining the Problem

So it really would be nice if we could just fire a JRuby script within the project root and expect it to be able to grab all of the project’s required classes.  However, there’s no way JRuby can do this for us.  What we need to do is actually manage a classloader of our own which searches through three separate locations relevant to the project:

  • Project compiled binaries (build/classes/)
  • ActiveObjects project compiled binaries (../ActiveObjects/bin/)
  • Project JAR dependencies (WebContent/WEB-INF/lib/*.jar)

While JRuby doesn’t provide any handy mechanism to do this (nor should they), Java does.  We can use a URLClassLoader instance from within JRuby and associate it with all of the given paths.  Using this URLClassLoader, we can load whatever class we need by String name and then - through the Java reflection API - access whatever methods/constructors are required.

If this sounds complicated, then you’re probably paying attention.  Classloaders and Java reflection both have notoriously verbose and complicated APIs.  In short, this isn’t something with which we want to pollute every single utility script we may need to write.  We need to develop some sort of Ruby API to wrap around all of this complexity.  Hopefully one which will enable us to access project classes in an intuitive (and memorable) manner.

Designing the Interface

Ruby lends itself extremely well to the development of so-called DSLs (Domain Specific Languages).  While we don’t need a full-blown DSL here, it would be really nice if we could have an intuitive syntax which could handle all of the complexity for us.  With that in mind, let’s imagine exactly what syntax we really want for our wrapper API:

#!/usr/bin/env jruby
 
require 'java'
require 'java_classes'
 
Utilities = get_class 'com.myproject.app.Utilities'
Utilities.createManager.optimize

In my project, the com.myproject.app.Utilties class contains a static method createManager() which returns an instance of IndexingEntityManager.  This ActiveObjects class in turn contains an optimize() instance method which calls the appropriate Lucene functions to optimize the index.  As you can see, our goal is to use the Utilities class within our script exactly as if it were a standard Ruby class (with the exception of the “dot” syntax as opposed to the double semi-colon for the class method).  Thankfully, this is an achievable goal.

If we write the get_class method to return a Ruby wrapper class corresponding to our custom-loaded project class, we could conceivably result in a syntax like the above.  Obviously, in the above example we’re assigning our wrapper class to the “Utilities” variable, and then treating that variable as if it were a proper class symbol (actually, as far as Ruby’s concerned, it may as well be).  So conceptually, that part of the problem is taken care of.

The second aspect to the syntax is actually treating project class static methods (and constructors, since we would potentially want to call “Utilities.new” and get a Utilities instance) as member methods of our wrapper class.  This is actually where much of the complicated will have to go.  Ruby does provide a mechanism for accomplishing this called “method_missing” (this is how ActiveRecord works).  However, we still need to write the logic needed to actually convert parameters, reflectively invoke methods, etc…

Implementation

So of course the first thing we need to take care of is the initialization of the classloader.  This is just hard work with the URLClassLoader API, so were going to assume we took care of it already.  :-)  For the sake of brevity, we’re going to pretend that the CLASSLOADER variable in the java_classes.rb file is an instance of URLClassLoader, properly initialized to hit the project classpath. 

The real interest of this mini API is in the JClassWrapper implementation.  It will be an instance of this Ruby class which is returned from the get_class method.  For the sake of simplicity, we’ll make the method_missing method within JClassWrapper to all the work.  Thus, the only things for which the get_class method is responsible are loading the class in question via CLASSLOADER and creating an instance of JClassWrapper to return.  The implementation is shown below:

def get_class(name)
    JClassWrapper.new java.lang.Class.forName(name, true, CLASSLOADER)
end

The really interesting code is in method_missing.  This is where we will handle both static methods and the special new method, which will be passed on to the wrapped Class’s constructor.  This is also where we need to worry about auto-converting the method parameters into values which will make sense to the wrapped Java method.  For the sake of simplicity, we’re not going to worry about wrapping anything like complex classes.  Instead, we’ll just assume that the parameters passed will either be already Java objects, or simple primitives like String or Fixnum.

The auto-conversion logic should look something like this (we can add to it as necessary):

def method_missing(sym, *args)
    jarg_types = java.lang.Class[args.size].new
    jargs = java.lang.Object[args.size].new
 
    for i in 0..(args.length - 1)
        if args[i].kind_of? String
            args[i] = java.lang.String.new args[i]
        elsif args[i].kind_of? Fixnum
            args[i] = java.lang.Integer.new args[i]
        elsif args[i].kind_of? JClassWrapper
            args[i] = args[i].java_class
        end
 
        jarg_types[i] = args[i].java_class
        jargs[i] = args[i]
    end
    # ...
end

As you can see, all this does is create and populate a types and a values array.  There are some basic, hard-coded conversions, and that’s about it.  This gives us all we need to pass values to the reflectively discovered static methods or constructor.  In fact, the only really interesting logic left to us is the actual reflective invocations:

def method_missing(sym, *args)
    # ...
    if sym == :new
        begin
            constructor = @clazz.getConstructor jarg_types
        rescue
            return super
        end
 
        return constructor.newInstance(jargs)
    elsif sym == :java_class
        return @clazz
    end
 
    begin
        method = @clazz.getMethod(sym.to_s, jarg_types)
    rescue
        return super
    end
 
    return method.invoke(nil, jargs) if defined? method
 
    super
end

Here we have some special logic for the new and java_class methods, since we don’t want to pass these directly to the wrapped class, but the rest of the logic is surprisingly simple.  Really all we need to do is find the corresponding static method by name and using the types array we populated earlier.  Then, using the java.lang.reflect.Method instance, we invoke the method passing the values array and nil for the instance (since it’s a static method).

One of the nice things about this is any Java values returned from these methods will be automatically handled and wrapped by JRuby.  Thus, we can do something like this if we really want to:

Person = get_class 'com.myproject.db.Person'
EntityManager = get_class 'net.java.ao.EntityManager'
 
manager = EntityManager.new(config[:uri], config[:user], config[:pass])
people = manager.find(Person.java_class)
 
people.each do |p|
    puts "Person: #{p.first_name} #{p.last_name} is #{p.age} years old"
end

You’ll notice we don’t have any special logic at work dealing with the EntityManager instance or the Person array and instances returned from the find method.  Regardless of our fancy ClassLoader tricks and class wrapping, we can still rely upon JRuby’s built-in Java integration facilities to take care of most of the heavy lifting.  The full source for the “java_classes.rb” file is available here.  Note, you will have to customize the values a bit depending on your project’s classpath.  Enjoy!

Wicket TextileLabel

8
Jul
2007

Well, first I must apologize for not updating my blog in some time. Loads of interesting (and time consuming) things have been happening recently, specifically related to my employment as well as a rather jam-packed holiday week in the US. On a slightly different (but related) note, I resigned from my full time job and am once again “programmer for hire” (if you’re interested, you can drop me an email: djspiewak [AT] gmail). Thankfully, all the closing details seem to be in order, so I’ll finally have a little more time to devote to this blog as well as to writings on EclipseZone.

In that vein I’ve spent a bit more time with Wicket (now Apache Wicket) recently, and I have to confess even more impressed with it than I was a year ago when I first looked at it. The separation of markup and code is a powerful concept that no other framework seems to have achieved to the same level without massive libraries of custom tags. For those of you who aren’t already familiar with Wicket, it’s an Open Source, component-based web framework. You create pages in Wicket by writing a standard HTML file, adding a wicket:id=”yadayada” attribute to the dynamic elements, then you add the corresponding component instances to the Page instance in code. No Java in your HTML, no HTML in your Java.

One of the things I stumbled upon in my latest run at the Wicket is the limitations of its MultiLineLabel component. MultiLineLabel lets you display large blocks of text with the characters appropriately escaped and all line breaks converted to proper <p></p> blocks. It’s not a complicated component, and this is glaringly obvious if you actually need something a bit more substantial.

The site I’m using to experiment has a need for large blocks of (preferably) formatted text. At first, I figured I’d just throw a MultiLineLabel up and call it done. However, the need for formatting seemed a bit more pressing, so I began to look at alternatives. And it occurred to me that perhaps the simplest way to enter formatted text is to use Textile. Unfortunately, this means I need some way to render Textile into HTML within Wicket.

After some Googling, I was able to positively ascertain that there are no Wicket components which provide Textile rendering. Not being one to give up there, I decided to roll my own. After all, one of Wicket’s major selling points is that it makes custom components dead easy, right?

Well, seems the hype is justified in this area too. Although, I must admit the documentation is sorely lacking in this area. I ended up cracking open the source for MultiLineLabel (which was surprisingly readable) and discovering that the key is to override the onComponentTagBody method. With a little more Googling, I found PLextile, which is the most complete Java Textile rendering library. A few minutes of quick hacking later, and I came up with this:

protected void onComponentTagBody(MarkupStream markupStream, ComponentTag openTag) {
    String text = (String) getModel().getObject();
    if (text == null) {
        text = "";
    }
 
    replaceComponentTagBody(markupStream, openTag, postTextilize(new TextParser().parseTextile(text, true)));
}

PLextile handles all the heavy lifting here, and parses out just about everything just fine. It’s main stumbling point is how it handles line breaks. According to Why’s comprehensive Textile reference, line breaks should be handled by wrapping the sections into <p></p> blocks, whereas PLextile was inserting <br/> tags. Quite frustrating, let me tell you.

I considered using RedCloth (Why-the-Lucky-Stiff’s Ruby Textile renderer, wrapped by Rails for the famous textilize method) through JRuby and Java 6 embedded scripting, but it seemed awfully heavy to fire up an entire JRuby interpreter instance just to parse some text, so the decision was made to steer away from that. Instead, I wrote a post-processor for PLextile (hence the postTextilize method in the example above). This method is actually where most of the code is for the component:

private String postTextilize(String textile) {
    textile = "<p>" + textile + "</p>";
    textile = textile.replace("<br />\\r<br />", "</p><p>");
    textile = textile.replace("<br />", "");
 
    return textile;
}

Anyway, wrap it all up into a WebComponent subclass and it’s ready to use in a page. Swap TextileLabel for your former MultiLineLabel usages, and you’re ready to go!

You can download the finished component here.

JRuby: The Future of Scalable Rails?

14
Jun
2007

So I was talking earlier today with my good friend, Lowell Heddings, regarding certain annoyances we had with web frameworks. The conversation started talking about the difficulties of developing PHP applications due to the lack of a debugger, but (as conversations on web frameworks are wont to do) eventually the migrated to Rails.

I mentioned how I’d always been a bit distrustful of a web framework which ran on the one-request-per-persistent-process model. My reasons for distrusting this sort of framework were mainly related to performance and scalability, but Lowell brought up an interesting point that I hadn’t considered before: process-shared sessions.

See, because Rails runs as a parallel share-nothing process (i.e. the mongrel instances don’t share memory state with one-another), trivial in-memory data can be a bit of a problem. Also, caching to disk can be a bit problematic since there are multiple processes attempting to access the on-disk data simultaneously. I’m sure many clever solutions have been mooted to solve this problem, but (I think) a new one occurred to me as we were discussing the problem. (caveat: I haven’t fleshed out this solution at all with any code. I’m posting it because Lowell thought it was an idea worth sharing) :-)

My solution to the problem drops back into one of the hottest topic in Ruby today: JRuby on Rails. JRuby allows you to run Rails applications in a Java-based and integrated environment, even to the extent of using existing Java tools, libraries and process containers. An ancillary project to JRuby even allows you to package up your Rails application within a WAR and host it directly within a Java application server like Tomcat or Glassfish.

Packaging Rails as a WAR obviously necessitates a bit of configuration that wouldn’t normally go into the deployment of a Rails application. For example, if you want to serve multiple requests with a Rails app concurrently, you would run multiple Mongrel instances and use an Apache mod_proxy configuration which would proxy requests to available server processes. Java web application, while they do run on the persistent-process model, are designed to be multi-threaded, rather than multi-process. Thus, Java web applications automatically scale to involve concurrent requests since all that is required is the spawning of a new thread within the application server.

Rails however, is designed to be hosted as a separate process and would have to be extensively modified to support this kind of scaling directly. The solution found by the JRuby-extras project is to allow multiple Rails instances to be controlled by a single Rails app WAR. The number of instances is controlled by a configuration option within the web.xml config file within the WAR. Thus, the JRuby WAR will spawn a new instance of the JRuby interpreter for each Rails process (as Rails expects), all hosted in separate threads within the same JVM instance, controlled by the Java app server. Thus, instead of going to all the hassle of configuring a new Mongrel instance and adding a mod_proxy rule to scale your Rails app, all that is necessary is to change a value in an XML file and to redeploy.

This single-process encapsulation of Rails in this way allows us to provide a solution for Lowell’s shared data problem. Instead of storing shared data (like application sessions or cached values) within the Rails process itself, the Rails application should use a Java class (hosted within the same WAR) to store the data. Thus, all shared application data should be stored at lower level than Rails, within the Java process itself. Java has some very solid concurrency APIs which would allow this sort of shared state without data corruption.

JRuby-on-Rails Diagram

As the application scaled and the shared data requirements increased, the SharedCache class (as we’ll christen it) could be modified to cluster, using Terracotta. The Rails WAR itself is already transparently clusterable through Java application servers like JBoss. As Lowell put it, it’s like an infinitely scalable memcached, without all the fuss.

Well, it’s a thought anyway…

Does Swing Need Saving?

21
Feb
2007

There’s been some discussion lately regarding various scripting languages and if they are (or aren’t) the salvation for the “dying” Swing API (here, here and here). However, all of these blog entries assume one critical fact: Swing is dead or at least dying. I call that assumption into question.

Actually, I was kind of surprised that none of the Sun fan-boys beat me to the punch. Over the years, I’ve shot my mouth of quite a bit against Swing. So it surprises me greatly that I’d be the first to step forward and try to defend Swing. In fact, if you had talked to me a year ago, likely I would have been leading the charge to bury Swing and move on. Apparently, some things have changed…

The first post to hit the blogosphere, JRuby can save Swing summed up the core assumptions of all three pretty quickly:

  • Swing apps are slow to build
  • Swing layout managers suck
  • Swing apps are hard to maintain
  • Swing is too powerful
  • No native features
  • Swing apps have a bad history

To start with, assuming that using Swing from within a scripting language solves any of these problems smacks of dynamically-typed delirium. When I first read the JRuby cannot save Swing post, I assumed that it would mention this minor fact, but instead it simply berated Swing further and proposed that it is “beyond saving”. Somehow, this seems a little bit of an extreme sentiment towards one of Java’s most established frameworks. Let’s look at item number one…

Swing apps are slow to build

That depends greatly on a number of factors, not the least of which is the capabilities of the developer in question. I can build a non-trivial Swing UI in a couple hours. I’m sure Romain Guy could do it in half that. Compare that to some developers who would take hours to build a simple, three element form. It’s all relative.

Some of the blog posts propose that using a dynamic language would help with this problem. Let’s take a look:

public class TestClass {
    public static void main(String... args) {
        JFrame frame = new JFrame("Test Frame");
 
        JLabel label = new JLabel("This is the header");
        label.setFont(label.getFont().deriveFont(label.getFont().getSize2D() + 10));
        frame.add(label, BorderLayout.NORTH);
 
        JPanel buttonPanel = new JPanel();
        frame.add(buttonPanel);
 
        buttonPanel.add(new JButton("Button 1"));
        buttonPanel.add(new JButton("Button 2"));
        buttonPanel.add(new JButton("Button 3"));
 
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(400, 200);
        frame.setVisible(true);
    }
}

This took me about 3 minutes to whip together. Obviously this is a toy example, but it does illustrate the point that Swing isn’t that cryptic or bulky. Now, let’s take a look at the corresponding JRuby code:

require 'java'
 
JFrame = javax.swing.JFrame
JLabel = javax.swing.JLabel
JPanel = javax.swing.JPanel
JButton = javax.swing.JButton
 
BorderLayout = java.awt.BorderLayout
 
frame = JFrame.new 'Test Frame'
 
label = JLabel.new 'This is the header'
label.font = label.font.deriveFont(label.font.size_2D + 10)
frame.add(label, BorderLayout::NORTH)
 
button_panel = JPanel.new
frame.add button_panel
 
button_panel.add JButton.new 'Button 1'
button_panel.add JButton.new 'Button 2'
button_panel.add JButton.new 'Button 3'
 
frame.default_close_operation = JFrame::EXIT_ON_CLOSE
frame.setSize(400, 200)
frame.visible = true

Now, this took me just as long to put together as the example in Java. And I had already built the UI! Ruby is 1) a nice dynamic language, and 2) I had already done the work. Shouldn’t this have gone much faster? Also, this doesn’t seem too much clearer to me than the Java example. I mean, it’s all Swing.

One of the posts proposed that a generic (possibly XML based) overlay be created on top of Swing which would simplify development by only using Swing indirectly. Well, people have already done this (it’s called XUL), and it isn’t very popular outside of Mozilla.org But let’s move on…

Swing layout managers suck

Well maybe… It greatly depends on the type of UI you’re trying to create. If you’re trying to create a form-based UI with lots of elements then I will concede the point. The reason being that most forms are laid out in a grid-like fashion. For example, something like this:


It’s very hard to do something like this in Swing because the only two grid-based layout managers are GridLayout and GridBagLayout. GridLayout is extremely limiting, requiring all cells to be exactly the same dimensions, and GridBagLayout is powerful to a fault (as well as having some glaring weaknesses, like no absolute cell sizes).

However, this single shortcoming in the Swing layout manager menagerie (lack of a good form layout) has been rectified in Java 6. More specifically, the problem was fixed with the introduction of GroupLayout, which is the layout manager used by the NetBeans GUI builder (formerly Matisse). Although GroupLayout’s API is somewhat cryptic (not to mention Java 6 only), it’s still a very powerful layout manager, even more than GridBagLayout. There are also a whole host of third-party layout managers available for Swing which excel at form based layouts. JGoodies’s FormLayout is a popular one. I myself have even gone so far as to port a layout manager from SWT, GridLayout (which resembles GridBagLayout in power without the complexity). This brings me to my next point…

Even if there were no solid layout managers available for Swing, it’s still very easy to create your own. In fact, this process is so simple, and so revealing about the way Swing layout managers work, that I would recommend anyone who’s serious about developing with Swing to pursue custom layout managers. I’ve written several layout managers over the years. While I only use one of them on a regular basis, I greatly value the lessons learned from each and every one of them. And honestly, Swing makes the task of layout manager creation significantly easier than many other GUI toolkits (such as SWT).

Swing apps are hard to maintain

Not true. Badly designed code is hard to maintain. Badly designed code is written by bad programmers. Bad programmers are incapable of using Swing properly (and even if they did, the rest of their code would be atrocious). In fact, Swing encourages best-practice coding in a lot of ways (a highly MVC based architecture for one). If anything, Swing-based apps are easier to maintain than those created using other APIs.

Swing is too powerful

This is a problem?

No native features

Well, it depends on what you mean when you say “no native features”. Does every element in a Swing UI correspond with a native peer? No. Are Swing elements indistinguishable from their native counterparts? Eh, depends on the platform and how good your eyes are. On Windows XP, the answer is often yes. On Vista, less often. On Mac the differences are acceptable, but on Linux the GTKLookAndFeel is terrible. Don’t get me wrong, it’s better than it was, but it still needs a lot of work before it’s truly production quality.

The “native features” case in which Swing falls drastically short is in integration with the native platform’s desktop features. For example:

  • Determining and firing native apps for a particular file association
  • Retrieving corresponding icons for a certain file association
  • Determining file associations in the first place
  • Access to any sort of platform-specific feature
  • …and so on

I won’t deny that SWT is miles ahead of Swing in this regard. However, there is some dissention over a) are these really the responsibility of the GUI toolkit? and b) what’s wrong with separate libraries like JDIC? Oh well, we’ll still chalk this up as a point for “the other side” (whoever that may be).

Swing apps have a bad history

This is flat out undeniable. Swing apps have a terrible reputation. I still walk into random IT departments, mention I’m a Java developer and get lectures about how slow, ugly and unreliable Java is; when in fact, these comments are really directed at legacy Swing applications.

Swing is a hard API to use properly. This is true mainly because it is an API worth using. This difficulty that programmers have with Swing is amplified by the fact that back in the day, many GUIs were designed visually with the aid of tools like Delphi or Visual Basic’s form editor. Obviously, these tools make it a lot easier to get a “cheap and dirty” UI out the door quickly, but the result really isn’t a GUI worth maintaining. Also, it led to a lot of bad programmers thinking that they were good programmers because they were able to create mediocre prototypes. Refer to “Swing apps are hard to maintain” for more on this point.

Also, until recently, the look and feels available for use with Swing were either highly esoteric and non-native or flat out ugly (or both). Without a solid look and feel to render the components well, Swing looks terrible. However, as of Java 5 Swing got a vastly improved Luna (Windows XP) look and feel. Java 6 introduced a half-way-there GTKLookAndFeel on linux, as well as sub-pixel rendering. Swing fonts have been the focal point of a lot of criticisms primarily because they (until recently) lacked sub-pixel rendering. (sub-pixel rendering allows fonts to look “smoother” on most screens) I think that you could make an argument that Swing on Windows XP looks just as good as any native application.

To Conclude…

Swing is in no need of a rescue from more “hip” languages like Ruby or Groovy. Nor is Swing languishing in the pit of unattractiveness. Rather, Swing is alive and well, and getting stronger by the day. Swing doesn’t need saving, what Swing needs is to be given another chance by the world.

JRuby Event Proxy

18
Feb
2007

One of the things which really which annoys me about JRuby is the lack of a clean syntax corresponding to Java’s anonymous inner classes. Now, Ruby has a neat little syntax trick called blocks. It really would be the ultimate solution if you could use Ruby blocks in things like Java event listeners instead of subclasses. Here’s a quick example:

test3.rb

require 'java'
 
JFrame = javax.swing.JFrame
JButton = javax.swing.JButton
FlowLayout = java.awt.FlowLayout
ActionListener = java.awt.event.ActionListener
 
class CustomActionListener < ActionListener
    def actionPerformed(e)
        puts 'Button Clicked'
    end
end
 
frame = JFrame.new 'Test Frame'
frame.layout = FlowLayout.new
 
button = JButton.new 'Click Me'
button.addActionListener CustomActionListener.new
frame.content_pane.add button
 
frame.setSize(200, 75)
frame.default_close_operation = JFrame::EXIT_ON_CLOSE
frame.visible = true

Notice anything annoying about the above code? We’re using this really nice, clean Ruby syntax with this incredibly ugly listener syntax (the custom class). Now, Ruby does have a slightly cleaner recourse called anonymous classes which is a little nicer, but still fairly ugly:

test2.rb

require 'java'
 
JFrame = javax.swing.JFrame
JButton = javax.swing.JButton
FlowLayout = java.awt.FlowLayout
ActionListener = java.awt.event.ActionListener
 
frame = JFrame.new 'Test Frame'
frame.layout = FlowLayout.new
 
button = JButton.new 'Click Me'
frame.content_pane.add button
 
listener = Class.new(ActionListener).new
def listener.actionPerformed(e)
    puts 'Button Clicked'
end
button.addActionListener listener
 
frame.setSize(200, 75)
frame.default_close_operation = JFrame::EXIT_ON_CLOSE
frame.visible = true

As you see, this is a little nicer primarily because there’s no extraneous named-class to be defined. However, it still lacks a truly clean syntax. What would be really nice is if we could write code like the following:

test.rb

require 'java'
require 'jruby_utils'
 
JFrame = javax.swing.JFrame
JButton = javax.swing.JButton
FlowLayout = java.awt.FlowLayout
ActionListener = java.awt.event.ActionListener
 
frame = JFrame.new 'Test Frame'
frame.layout = FlowLayout.new
 
button = JButton.new 'Click Me'
button.addActionListener proxy_method(ActionListener, 'actionPerformed') { |e|
    puts 'Button Clicked'
}
frame.content_pane.add button
 
frame.setSize(200, 75)
frame.default_close_operation = JFrame::EXIT_ON_CLOSE
frame.visible = true

I think that this is pretty clean. There’s no class definition anywhere. In fact, it’s all done in a block with the ActionEvent instance passed as a parameter.

This is cute and all, but it doesn’t seem to be very useful. To make this work, we’re utilizing a fictional method: “proxy_method”. Intuitively, this method should take a Class and a String defining a method name to override as parameters (along with a block), and then reflectively wrap the block into an overriding method within a subclass of the specified Class. In Java, this would be absolutely impossible - not to mention unnecessary and somewhat bizarre since Java a) defines no such “block” syntax, and b) Java already has anonymous inner classes, so there really isn’t a problem to solve. However, Ruby has a far more dynamic nature and it is actually possible for us to write proxy_method. The implementation looks something like this:

jruby_utils.rb

require 'java'
 
def proxy_method(superclass, name, &block)
    clazz = Class.new(superclass)
    instance = clazz.new
    instance.instance_eval do
        @name = name
        @block = block
 
        def method_missing(missing, *args)
            if missing.id2name == @name
                @block.call args
            else
                super
            end
        end
    end
    instance
end

As you can see, this is pretty much doing reflectively what we worked out mentally above. proxy_method accepts two parameters, a Class and a String. The third parameter is a special “block parameter” which is assigned by Ruby to the specified block wrapped into a Proc instance. (the specified block being the block used in conjunction with the proxy_method invocation in the example above) Then, the method dynamically creates an anonymous class with the specified superclass and assigns it to the clazz variable. clazz (which really represents a bona fide type) is instantiated and a dynamic code block is invoked. (a dynamic instance block is effectively a reflective body to a class) The name and block parameters are assigned to instance fields within the dynamic block and a new method is defined (or rather overridden).

Now, in Ruby, the method_missing method is a special method which is invoked by Ruby in the case of a method invocation which cannot be resolved against the specified instance. The default implementation (in Object) raises an exception, but by overriding this method, developers can easily add arbitrary methods to instances dynamically. In this case, we check to see if the missing method’s name matches the method name we were passed as a parameter of proxy_method. If the names do indeed match, then we invoke the block we were passed in the first place, passing all of the parameters which were intended for the missing method. Then, the value returned from the block is returned from method_missing. (though, in the case of an event listener this really isn’t necessary)

The a vitally important part of our code is the else statement within method_missing. This call passes the method missing invocation up the hierarchy if it doesn’t match the method name with which we are concerned. This is important because this allows either the runtime to throw an exception (in case of a truly missing method), or another method_missing implementation in a super-class to also check for method to reflectively invoke. In our case, the method_missing call will get sent on to the JavaObject class (defined by JRuby) which will check for any corresponding methods in the associated Java class. If none are found, it too will send the method_missing invocation up the hierarchy where it will eventually reach Object, which will raise an exception.

Just as an aside, proxy_method is also suitable for usage in other situations such as creating Java threads directly in JRuby. Consider the following example:

test4.rb

require 'java'
require 'jruby_utils'
 
JThread = java.lang.Thread
thread = proxy_method(JThread, 'run') { puts '...in another thread' }
thread.start

This code will print “…in another thread” once to stdout. But the cool bit is this is actually equivalent to the following code:

test4.rb

require 'java'
 
JThread = java.lang.Thread
class ThreadImpl < JThread
    def run
        puts '...in another thread'
    end
end
 
thread = ThreadImpl.new
thread.start

Notice how much cleaner it is with proxy_method? :-)

Hopefully, you find this to be a useful overview of Ruby method reflection in general, and more specifically, a useful method which can greatly simplify any JRuby code using Java APIs designed for use with anonymous inner classes.