-
Realjenius.com is ChangingR.J. LorimerTue, Sep 8 2009 @ 3:54 am
-
FriendFeed's Pseudo-ODBR.J. LorimerFri, Feb 27 2009 @ 11:29 pm
-
RubotoR.J. LorimerThu, Feb 26 2009 @ 4:33 pm
-
Constructor CompletionR.J. LorimerTue, Jan 20 2009 @ 3:44 pm
-
The Call of ChrismathuluR.J. LorimerFri, Nov 7 2008 @ 2:38 pm
Getting True Java Classes in JRuby
This is an interesting thing I ran across when dealing with JRuby 1.1.4 and Swing - some of this may be just my lack of understanding of some of the Java integration features, some of it may be lingering bugs in the Java integration, and some of it may just be what has to be done to make it work; anyway - here goes.
I was recently developing a Swing app in JRuby (something which I plan to cover in more detail in future blog posts), and was developing an implementation of a javax.swing.table.TableModel in JRuby. One of the things I wanted to implement was the Class getColumnClass(int col) method of AbstractTableModel, as this allows you to automatically inherit smart cell editors such as checkboxes.
However, using a combination of Quaqua L&F, JTable, and JRuby type wrappers was causing an obscure NPE in my code. I was doing something like this initially:
require 'java' module Lang include_package 'java.lang' end # ... In the actual implementation... def get_column_class(col) val = Lang::String::class case col when 1 then val = Lang::Boolean::class end end
This was failing miserably - I was getting a wrapper around the class object in Ruby - if I did a puts val it would simply print out ‘class’, and if I did a puts val.name it would still simply print out ‘class’. My guess was that I wasn’t getting to the class variable in Java; it was likely just a name collision issue in Ruby.
So I re-focused - as a temporary hack I tried this:
def get_column_class(col) val = Lang::String.new.class case col when 1 then val = Lang::Boolean::TRUE.class end end
This time, hoping to surface the real Java class object, I worked with instances (in turn trying to call the corresponding getClass in the Java world. However, while I didn’t wind up with just ‘Class’ again, I didn’t get Java objects either. I got Ruby class objects.
I realized after trying this that my untrained Ruby brain had hit the same problem in both cases - I was simply accessing the Ruby Object#class property - first it was ‘class’ because I was on a class object, and then it was corresponding ruby classes for the individual objects. Interestingly enough, the Ruby String class wrapper unboxed to the ‘java.lang.String’ class object just fine, but the Ruby Boolean class wrapper, which was ‘TrueClass’ was being returned as something else entirely.
I was left with what I saw as two options - one is probably faster, but feels dirty, and the other is probably slower, but is more explicit.
Option 1
val = Lang::String.new.get_class # get_class triggers the getter in Java
Option 2
val = Lang::Class::for_name 'java.lang.String'
The latter is the one that is likely slower in Java (and in turn will be in JRuby as well). However, since I don’t need to call it all the time, it is the choice I made for my table model by initializing the column types in the constructor - I also added a method to the Lang module to help:
My Solution of Choice
module Lang include_package 'java.lang' def get_java_class(str) return Lang::Class::for_name(str) end end # ... table model implementation including Lang def initialize @col_types = [ get_java_class 'java.lang.String', get_java_class 'java.lang.Boolean' ] end
Anyone else have a more elegant solution?
- Login to post comments
