From: "Mauricio Fernández" Date: 2003-06-25T22:29:15+09:00 Subject: Ruby/Java integration through JNI: working implementation This is the idea that popped out during the last discussion in Euruko03. (sorry, don't remember the name of the guy who exposed it :) It has taken me a little bit more than I first thought (the Chinese kept me busy :), but 3 days later I have the first working code. I have created a straight-forward mapping for most of the JNI API, which becomes available as a Ruby extension. This allows the use of the low-level interface specified in http://java.sun.com/products/jdk/1.2/docs/guide/jni/. This part is written in C (around 4000 LOCs at the moment). I have built a simple reflection system that maps Java classes to Ruby space, by using the reflection API to get information on all the available methods. At the moment it is written in Ruby but it should probably be coded in C for speed (this can be done later w/o any problem) and allows to call methods transparently as if they were implemented in Ruby. At the moment, the following is working: * creating objects and manipulating native types * static methods w/ arbitrary parameters and any return value (native or object types) * methods " " " " * Java objects arrays * non virtual method calls * method overloading (dispatching is performed depending on arg types) * seamless conversion of Ruby String and Numeric types to the required Java types according to method signatures Things I have to work on: * think about Java exceptions: map them to Ruby or signal them somehow? * dynamic definition of Java classes and adding native methods at run-time (for instance to call Ruby Procs in callbacks) * more automated conversions: Arrays to Java's type[] and vice-versa * wrap Java's reflection API completely, providing convenient metaclass abstractions & such * add more methods to the wrapped Java objects to integrate them better w/ Ruby * cover more code w/ unit tests (esp. the reflection part) This is real example of what I'm doing: Given Simple.java: public class Simple { public String doStuff(String a) { return "I was called with argument \"" + a.toString() + "\"" ; } public String doStuff(String a, String b) { return a + b; } public boolean compareStrings(String a, String b) { System.out.println("I was passed " + a + " and " + b); return a.equals(b); } public int compare2(String a, String b) { System.out.println("I was passed " + a + " and " + b); return a.compareTo(b); } public int sum(String a, String b) { System.out.println("Adding " + a + " and " + b + " (inside Java!!!)"); int i = Integer.parseInt(a) + Integer.parseInt(b); System.out.println("The result will be: " + i); return i; } } I can instantiate the Java object and access its methods from Ruby as follows: require 'reflect' require 'rjni' vm = RJNI::JVM.new "-cp ." reflector = RJNI::Reflect.new(vm) sclass = reflector["Simple"] o = sclass.new_object r = o.doStuff("foo passed from Ruby!!!!") puts "Result: #{r}" r = o.doStuff("hello, ", "world!") puts "Result: #{r}" r = o.compareStrings("ruby","matz") puts "Result: #{r.to_b}" r = o.compareStrings("matz","matz") puts "Result: #{r.to_b}" r = o.compare2("ruby","matz") puts "Result: #{r.to_i}" r = o.compare2("matz","matz") puts "Result: #{r.to_i}" r = o.sum("1", "1") puts "Result: #{r.to_i}" Result: batsman@tux-chan:~/src/rjni$ LD_LIBRARY_PATH=/usr/local/java/j2sdk1.4.1/jre/lib/i386/:/usr/local/java/j2sdk1.4.1/jre/lib/i386/client ruby tc_reflect.rb Result: I was called with argument "foo passed from Ruby!!!!" Result: hello, world! I was passed ruby and matz Result: false I was passed matz and matz Result: true I was passed ruby and matz Result: 5 I was passed matz and matz Result: 0 Adding 1 and 1 (inside Java!!!) The result will be: 2 Result: 2 The code is right now in a state of flux as I am quickly adding functionality but I am going through quite fast so I should be able to release something soon. -- _ _ | |__ __ _| |_ ___ _ __ ___ __ _ _ __ | '_ \ / _` | __/ __| '_ ` _ \ / _` | '_ \ | |_) | (_| | |_\__ \ | | | | | (_| | | | | |_.__/ \__,_|\__|___/_| |_| |_|\__,_|_| |_| Running Debian GNU/Linux Sid (unstable) batsman dot geo at yahoo dot com need help: my first packet to my provider gets lost :-( sel: dont send the first one, start with #2 * netgod is kidding