From: "Mauricio Fernández" Date: 2003-06-27T06:05:28+09:00 Subject: Re: API for Ruby/Java integration through JNI (feedback needed!) On Fri, Jun 27, 2003 at 05:39:28AM +0900, gabriele renzi wrote: > > reflector = Reflect.new vm # create the "reflector", only need one > > theklass = reflector["Simple"] > > object = theklass.new # mimic Ruby's object creation > > reflector sounds wierd to me.. somthing better? :) it's just a variable name :) Now, if you don't like Reflect, I can still change it. > > >Now, the things I need feedback on: > > * static methods: should they magically pop up in theklass, so that they > > work as in Class objects in Ruby? > > it would be cool if Reflect.new worked like Class.new, so that static > java methods would automagically become class methods. anyway, a > solution that just mimic this would be good enough. It does now. Static methods seem to become singleton methods of the class objects. You can do aklass.java_instance_methods to get an array of Method objects, and aklass.java_methods to get the static methods (singleton methods) of the class. Moreover, classes are objects too. You can get the class of a class, too. Take a look at this example: Simple.java ============ package net.thekode.rjni; 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; } public static void superTest() { System.out.println("Super static test!!"); } } test_reflect.rb ================= require 'reflect' require 'rjni' RJNI::JVM.new #"-cp ." reflector = RJNI::Reflect.new sclass = reflector["net.thekode.rjni.Simple"] puts "Class: #{sclass}" puts "Instance methods:" puts "=" * 40 sclass.java_instance_methods.each { |x| p x } puts "=" * 40 puts puts "Class methods:" puts "=" * 40 sclass.java_methods.each { |x| p x } puts "=" * 40 sclass.superTest ### Ruby way!!! puts o = sclass.new puts "Created object <#{o.to_s}> of class <#{sclass}>" puts "Getting metaclass of <#{o}>" metaclass = sclass.java_class puts "Metaclass <#{metaclass}>" puts "Listing methods of the class (using metaclass.getMethods):" puts("=" * 40) metaclass.getMethods.to_a.each { |x| p x } puts("=" * 40) puts "Now let's execute some methods...\n" 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}" Output ======= Class: net.thekode.rjni.Simple Instance methods: ======================================== public java.lang.String net.thekode.rjni.Simple.doStuff(java.lang.String) public java.lang.String net.thekode.rjni.Simple.doStuff(java.lang.String,java.lang.String) public boolean net.thekode.rjni.Simple.compareStrings(java.lang.String,java.lang.String) public int net.thekode.rjni.Simple.compare2(java.lang.String,java.lang.String) public int net.thekode.rjni.Simple.sum(java.lang.String,java.lang.String) public native int java.lang.Object.hashCode() public final native java.lang.Class java.lang.Object.getClass() public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException public final void java.lang.Object.wait() throws java.lang.InterruptedException public boolean java.lang.Object.equals(java.lang.Object) public java.lang.String java.lang.Object.toString() public final native void java.lang.Object.notify() public final native void java.lang.Object.notifyAll() ======================================== Class methods: ======================================== public static void net.thekode.rjni.Simple.superTest() ======================================== Super static test!! Created object of class Getting metaclass of Metaclass Listing methods of the class (using metaclass.getMethods): ======================================== public java.lang.String net.thekode.rjni.Simple.doStuff(java.lang.String) public java.lang.String net.thekode.rjni.Simple.doStuff(java.lang.String,java.lang.String) public boolean net.thekode.rjni.Simple.compareStrings(java.lang.String,java.lang.String) public int net.thekode.rjni.Simple.compare2(java.lang.String,java.lang.String) public int net.thekode.rjni.Simple.sum(java.lang.String,java.lang.String) public static void net.thekode.rjni.Simple.superTest() public native int java.lang.Object.hashCode() public final native java.lang.Class java.lang.Object.getClass() public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException public final void java.lang.Object.wait() throws java.lang.InterruptedException public boolean java.lang.Object.equals(java.lang.Object) public java.lang.String java.lang.Object.toString() public final native void java.lang.Object.notify() public final native void java.lang.Object.notifyAll() ======================================== Now let's execute some methods... 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 > > * should I provide #instance_methods and such? > > at the moment I've made #java_instance_methods that returns an Array > > with RJNI::Object objects that represent the methods. > are you talking about ruby reflection's apis? anyway, I supose yes It's in fact redundant as you can get most things through JNI, and you can always use JNI to use the reflection API :) > > * should instance methods be directly invocable such as in the example > > above, or by doing object.send_java("doStuff", *args) or such? > > It is not as pretty, but OTOH this way there's no name collisions. > > what kind of name collision could happen ? classes in Java with methods like object_id, instance_methods, class, method_missing, etc... > anyway I have no idea about the possibility to do this stuff, so > forget my desires if you wish :) everything doable, by experience: I have done most of it by now :) -- _ _ | |__ __ _| |_ ___ _ __ ___ __ _ _ __ | '_ \ / _` | __/ __| '_ ` _ \ / _` | '_ \ | |_) | (_| | |_\__ \ | | | | | (_| | | | | |_.__/ \__,_|\__|___/_| |_| |_|\__,_|_| |_| Running Debian GNU/Linux Sid (unstable) batsman dot geo at yahoo dot com We are MicroSoft. You will be assimilated. Resistance is futile. -- Attributed to B.G., Gill Bates