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 :slight_smile:

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
Oracle Java Technologies | Oracle. 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 :frowning:
sel: dont send the first one, start with #2

  • netgod is kidding

Yet An other JRuby ?? :slight_smile:

···

Do you Yahoo!?
SBC Yahoo! DSL - Now only $29.95 per month!

You are a star!!!

···

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 :slight_smile:

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
Oracle Java Technologies | Oracle. 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.

    -A.

Armin Roehrl, http://www.approximity.com
We manage risk

Why do you think so?
JRuby is pure Java implementation of Ruby langauge, not a binding of Ruby
to Java. Of course you could use it in that way but such usage is somewhat
limited, especially existing Ruby bindings to other C/C++ libraries can’t
be used as is.

···

On Thu, Jun 26, 2003 at 12:44:52AM +0900, D T wrote:

Yet An other JRuby ?? :slight_smile:

/ Alexander Bokovoy


On the eighth day, God created FORTRAN.

This approach is very different from JRuby. I am accessing Java
through the JNI and later using the reflection API to map all the
methods to Ruby.

It offers quite a good integration (although by necessity not as tight)
but has the following advantages:

  • uses matz’ interpreter: faster as it is in C and you get bug-for-bug
    compatibility with itself :slight_smile:
  • easy to develop: I’ve written it in 2 days and have quite some things
    running in only 5000 lines of code.

Cons:

  • method dispatch to Java is slower at the moment (esp. w/ the current
    implementation), but I believe it can be done at least as fast as in
    JRuby if not faster.
  • integration won’t be as tight, but should be good enough. In the
    worst case, you can do anything through the low-level JNI API.
···

On Thu, Jun 26, 2003 at 12:44:52AM +0900, D T wrote:

Yet An other JRuby ?? :slight_smile:


_ _

__ __ | | ___ _ __ ___ __ _ _ __
'_ \ / | __/ __| '_ _ \ / ` | ’ \
) | (| | |
__ \ | | | | | (| | | | |
.__/ _,
|_|/| || ||_,|| |_|
Running Debian GNU/Linux Sid (unstable)
batsman dot geo at yahoo dot com

It’s computer hardware, of course it’s worth having
– Espy on #Debian

D T wrote:

Yet An other JRuby ?? :slight_smile:

Not quite, and the JNI route may have an advantage.

JRuby implments the Ruby 1.6.7 interpreter; we’re on the verge of a
proper Ruby 1.8 release. Perhaps it’s less hard than I imagine,
but updating JRuby with each change to the latest stable Ruby release
is a task.

On the other hand, allowing calls into Java via JNI sidesteps this
problem. I think, though, that it also sidesteps the ability to load
and execute Ruby scripts from Java. :frowning:

James

···

Do you Yahoo!?
SBC Yahoo! DSL
http://pa.yahoo.com/*http://rd.yahoo.com/evt=1207/*http://promo.yahoo.com/sbc/

  • Now only $29.95 per month!

Ooops (and sorry), thank you guys.
When we talk about using Java stuff in Ruby, immediately, I thought about JRuby.
You are all right, JRuby is build on java.
Here we are using Java stuff through JNI layer.
Mmmm… It sound very interesting now. ( I like to try it )

Thanks.

···

D T tran55555@yahoo.com wrote:
Yet An other JRuby ?? :slight_smile:


Do you Yahoo!?
SBC Yahoo! DSL - Now only $29.95 per month!


Do you Yahoo!?
SBC Yahoo! DSL - Now only $29.95 per month!

You can always use JNI the other way around, to expose for instance
rb_eval_string_protect to Java. Then you have to wrap Ruby objects to
be able to manipulate them.

However in my mind it makes more sense to have Ruby driving everything
and using Java classes as needed.

···

On Thu, Jun 26, 2003 at 01:08:48AM +0900, james_b wrote:

D T wrote:

Yet An other JRuby ?? :slight_smile:

Not quite, and the JNI route may have an advantage.

JRuby implments the Ruby 1.6.7 interpreter; we’re on the verge of a
proper Ruby 1.8 release. Perhaps it’s less hard than I imagine,
but updating JRuby with each change to the latest stable Ruby release
is a task.

On the other hand, allowing calls into Java via JNI sidesteps this
problem. I think, though, that it also sidesteps the ability to load
and execute Ruby scripts from Java. :frowning:


_ _

__ __ | | ___ _ __ ___ __ _ _ __
'_ \ / | __/ __| '_ _ \ / ` | ’ \
) | (| | |
__ \ | | | | | (| | | | |
.__/ _,
|_|/| || ||_,|| |_|
Running Debian GNU/Linux Sid (unstable)
batsman dot geo at yahoo dot com

Sic transit discus mundi
– From the System Administrator’s Guide, by Lars Wirzenius

Ok, so in theory we can start developing our GUI applications using the SWT
and the Eclipse platform?

That’s great!

Which specific versions of the jsdk are/will be supported?

Regards,
Rodrigo

···

----- Original Message -----
From: “Mauricio Fernández” batsman.geo@yahoo.com
To: “ruby-talk ML” ruby-talk@ruby-lang.org
Sent: Wednesday, June 25, 2003 1:22 PM
Subject: Re: Ruby/Java integration through JNI: working implementation

On Thu, Jun 26, 2003 at 01:08:48AM +0900, james_b wrote:

D T wrote:

Yet An other JRuby ?? :slight_smile:

Not quite, and the JNI route may have an advantage.

JRuby implments the Ruby 1.6.7 interpreter; we’re on the verge of a
proper Ruby 1.8 release. Perhaps it’s less hard than I imagine,
but updating JRuby with each change to the latest stable Ruby release
is a task.

On the other hand, allowing calls into Java via JNI sidesteps this
problem. I think, though, that it also sidesteps the ability to load
and execute Ruby scripts from Java. :frowning:

You can always use JNI the other way around, to expose for instance
rb_eval_string_protect to Java. Then you have to wrap Ruby objects to
be able to manipulate them.

However in my mind it makes more sense to have Ruby driving everything
and using Java classes as needed.


_ _

__ __ | | ___ _ __ ___ __ _ _ __
'_ \ / | __/ __| '_ _ \ / ` | ’
) | (| | |
__ \ | | | | | (| | | | |
.__/ _,
|_|/| || ||_,|| |_|
Running Debian GNU/Linux Sid (unstable)
batsman dot geo at yahoo dot com

Sic transit discus mundi
– From the System Administrator’s Guide, by Lars Wirzenius

You can always use JNI the other way around, to expose for instance
rb_eval_string_protect to Java. Then you have to wrap Ruby objects to
be able to manipulate them.

However in my mind it makes more sense to have Ruby driving everything
and using Java classes as needed.

Given the choice, that would be mine, but I’m thinking of cases where
the primary code is Java, and being able to load and run Ruby scripts
inside a Java app would allow for considerable flexability.

James

Right now I’m linking against Blackdown 1.4.1, but AFAIK JNI is defined
from 1.2 on, and that’s all I use for the moment. I’ll check to make
sure that I’m not using incompatible APIs.

···

On Thu, Jun 26, 2003 at 02:52:39AM +0900, Rodrigo B. de Oliveira wrote:

Ok, so in theory we can start developing our GUI applications using the SWT
and the Eclipse platform?

That’s great!

Which specific versions of the jsdk are/will be supported?


_ _

__ __ | | ___ _ __ ___ __ _ _ __
'_ \ / | __/ __| '_ _ \ / ` | ’ \
) | (| | |
__ \ | | | | | (| | | | |
.__/ _,
|_|/| || ||_,|| |_|
Running Debian GNU/Linux Sid (unstable)
batsman dot geo at yahoo dot com

How do I type “for i in *.dvi do xdvi $i done” in a GUI?
– Discussion in comp.os.linux.misc on the intuitiveness of interfaces

Ok. A thought just occurred me. By using the proxies infrastructure in the
java
platform you can even create the illusion of ruby classes implementing java
interfaces. This
would raise the level of integration between the platforms and expose a
wider range of
APIs to ruby users.

What do you think?

Rodrigo

···

----- Original Message -----
From: “Mauricio Fernández” batsman.geo@yahoo.com
To: “ruby-talk ML” ruby-talk@ruby-lang.org
Sent: Wednesday, June 25, 2003 2:56 PM
Subject: Re: Ruby/Java integration through JNI: working implementation

On Thu, Jun 26, 2003 at 02:52:39AM +0900, Rodrigo B. de Oliveira wrote:

Ok, so in theory we can start developing our GUI applications using the
SWT
and the Eclipse platform?

That’s great!

Which specific versions of the jsdk are/will be supported?

Right now I’m linking against Blackdown 1.4.1, but AFAIK JNI is defined
from 1.2 on, and that’s all I use for the moment. I’ll check to make
sure that I’m not using incompatible APIs.


_ _

__ __ | | ___ _ __ ___ __ _ _ __
'_ \ / | __/ __| '_ _ \ / ` | ’
) | (| | |
__ \ | | | | | (| | | | |
.__/ _,
|_|/| || ||_,|| |_|
Running Debian GNU/Linux Sid (unstable)
batsman dot geo at yahoo dot com

How do I type “for i in *.dvi do xdvi $i done” in a GUI?
– Discussion in comp.os.linux.misc on the intuitiveness of interfaces

Ok. A thought just occurred me. By using the proxies infrastructure in the
java
platform you can even create the illusion of ruby classes implementing java
interfaces. This
would raise the level of integration between the platforms and expose a
wider range of
APIs to ruby users.

You mean using java.lang.reflect.Proxy?

What do you think?

It’s a great idea!! I annotate it in my mental TODO list.

···

On Thu, Jun 26, 2003 at 03:08:08AM +0900, Rodrigo B. de Oliveira wrote:


_ _

__ __ | | ___ _ __ ___ __ _ _ __
'_ \ / | __/ __| '_ _ \ / ` | ’ \
) | (| | |
__ \ | | | | | (| | | | |
.__/ _,
|_|/| || ||_,|| |_|
Running Debian GNU/Linux Sid (unstable)
batsman dot geo at yahoo dot com

‘Ooohh… “FreeBSD is faster over loopback, when compared to Linux
over the wire”. Film at 11.’
– Linus Torvalds

You mean using java.lang.reflect.Proxy?

Exactly.

What do you think?

It’s a great idea!! I annotate it in my mental TODO list.

Cool!

Rodrigo