Java_method and java_send in master/1.4

I’ve just finished adding part of the Java Integration proposal, the
“java_send” and “java_method” methods. This is likely the only part of
the “grand unified theory of Java integration” that will get into 1.4,
so I wanted to give a few quick examples.

The “java_send” method is for calling an overloaded or
unfortunately-named Java method from Ruby when all other mechanisms
fail. Here’s a couple examples:

import java.util.ArrayList
list = ArrayList.new
list.java_send :add, [Java::int, java.lang.Object], 0, ‘foo’
puts list.java_send :toString # => “[foo]”

This works for all instance methods. I have not implemented it for
static methods…does it seem like I should?

Now it’s likely that java_send will be slower than you want in some
cases. It’s going to dig into reflection, find the right method, wrap
it in appropriate clothes, and invoke it. But you may want to save the
object it finds and dispatch directly yourself. That’s where
java_method comes in.

With the “java_method” method you can get a reference to any
overloaded Java method as a Ruby Method or UnboundMethod object:

get a bound Method based on the add(int, Object) method from ArrayList

add = list.java_method :add, [Java::int, java.lang.Object]
add.call(0, ‘foo’)

get an UnboundMethod from the ArrayList class:

toString = ArrayList.java_method :toString
toString.bind(list).call # => [foo, foo]

get a bound Method for a static method on either an instance or a

class
JInteger = java.lang.Integer
valueOf = JInteger.java_method :valueOf, [Java::int]
valueOf.call(1) # => a new java.lang.Integer object for value 1

valueOf = JInteger.new(1).java_method :valueOf, [Java::int]

etc

Note that either mechanism should allow you to call the “int”
overloads of a “long” method when that’s really what you need to do.
These should provide workarounds for almost all cases where JRuby
selects the wrong overload, and you should hopefully never have to dig
into the JavaClass/JavaObject/JavaMethod subsystem again.

Both of these have specs in spec/java_integration/methods, and I’m
open to suggestions for improvement.

  • Charlie

To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email

Hello Charlie,

Seems interesting, however I’m wondering if these additions can change
the way method dispatching works in Ruby, mainly speaking to answer
this question:

On 9/28/09, Charles Oliver N. [email protected] wrote:

list = ArrayList.new
java_method comes in.
toString.bind(list).call # => [foo, foo]
overloads of a “long” method when that’s really what you need to do.
To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email

To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email

Hi Charles,

This change has made some codes unable to work anymore. I want to
update so that my programs work on the latest version, but I don’t
understand how to change them.

Here’s simplified one.

  • Java interface:
    package vanilla;

import java.util.List;

public interface Calculable {
List dimension(long base);
}

  • implementation
    class Calculation
    include Java::vanilla.Calculable
    def dimension(base)
    x = base + 1
    y = base + 2
    z = base - 1
    return x, y, z
    end
    end
    Calculation.new

  • Java program to invoke method
    package vanilla;

import java.util.List;
import org.jruby.embed.PathType;
import org.jruby.embed.ScriptingContainer;

public class Calculation {
private final String filename = “ruby/calculation.rb”;

private Calculation() {
    ScriptingContainer container = new ScriptingContainer();
    Object receiver = container.runScriptlet(PathType.CLASSPATH, 

filename);
Calculable c = container.getInstance(receiver,
Calculable.class);
List xyz = c.dimension(10L);
for (long v : xyz) {
System.out.print(v + ", ");
}
System.out.println();
}

public static void main(String[] args) {
    new Calculation();
}

}

When I ran this, I got a ClassCastException because contents of the
list, xyz, were converted to java.langByte type.

Exception in thread “main” java.lang.ClassCastException:
java.lang.Byte cannot be cast to java.lang.Long
at vanilla.Calculation.(Calculation.java:15)
at vanilla.Calculation.main(Calculation.java:22)
Java Result: 1

The code above had worked find before this change was applied.
Probably, I need to convert return type explicitly in Ruby code. But,
I don’t understand how to change my Ruby code. How and where can I
find the way of fixing this?

-Yoko

On Mon, Sep 28, 2009 at 12:10 AM, Charles Oliver N.
[email protected] wrote:

list = ArrayList.new
java_method comes in.
toString.bind(list).call # => [foo, foo]
overloads of a “long” method when that’s really what you need to do.
To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email


To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email

I dug this into and found current solution I can do on 1.4.0RC1.

Ruby code should be below:

class Calculation
include Java::vanilla.Calculable
def dimension(base)
x = java.lang.Long.new base + 1
y = java.lang.Long.new base + 2
z = java.lang.Long.new base - 1
return x, y, z
end
end
Calculation.new

I guess, I hit the issue JRUBY-4039, but explicit conversion also
seems not to work. I tried to convert the array when it is returned
to a Java world:

return [x, y, z].to_java(:long)

but, this raised following exception at the line the dimension method
was called.

Exception in thread "main" java.lang.ClassCastException: [J cannot

be cast to java.util.List

So, I tried the following code next so that conversions are done
within a Ruby world:

list = Java::java.util.ArrayList.new
[x, y, z].to_java(:long).each { |e| list.add e }
return list

Again, I got the exception when the elements of the List was referenced.

Exception in thread “main” java.lang.ClassCastException:
java.lang.Byte cannot be cast to java.lang.Long

Should I avoid using [x, y, z].to_java(:long), when I use Ruby code
with a Java program?

-Yoko

On Fri, Oct 2, 2009 at 12:02 PM, Yoko H. [email protected] wrote:

x = base + 1
import java.util.List;
List xyz = c.dimension(10L);

Probably, I need to convert return type explicitly in Ruby code. But,

the “grand unified theory of Java integration” that will get into 1.4,

overloaded Java method as a Ruby Method or UnboundMethod object:
JInteger = java.lang.Integer
into the JavaClass/JavaObject/JavaMethod subsystem again.


To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email

Sorry about this Yoko. Someone else reported it in JRUBY-4039, and I
just posted about the fix to dev list. I’d appreciate your feedback
there, but I have fixed it on master…

On Fri, Oct 2, 2009 at 6:02 AM, Yoko H. [email protected] wrote:

  x = base + 1
import java.util.List;
    List xyz = c.dimension(10L);

Probably, I need to convert return type explicitly in Ruby code. But,

the “grand unified theory of Java integration” that will get into 1.4,

overloaded Java method as a Ruby Method or UnboundMethod object:
JInteger = java.lang.Integer
into the JavaClass/JavaObject/JavaMethod subsystem again.


To unsubscribe from this list, please visit:

  http://xircles.codehaus.org/manage_email


To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email

I’m just wondering if it will help, method dispatching in Java is
totally
different from Ruby,
As you saw in the link, if we have a class A that has 2 methods ‘g’
which
calls ‘f’, and a subclass B from A, and we override method ‘f’ in B,
then
we called new B().g() , we will still get A’s ‘f’ method. This is in
contrast to Ruby’s behavior where the overridden ‘f’ will be called.

Sorry for bothering with this, just wanted to know if that’s possible or
not
now.
Thanks.

On Thu, Oct 8, 2009 at 6:45 AM, Charles Oliver N.

Hmm, I’m not sure how the changes I proposed would fit into the post
you linked. Can you elaborate?

On Sun, Sep 27, 2009 at 10:54 PM, Khaled al Habache [email protected]
wrote:

so I wanted to give a few quick examples.
This works for all instance methods. I have not implemented it for

valueOf = JInteger.java_method :valueOf, [Java::int]


To unsubscribe from this list, please visit:

  http://xircles.codehaus.org/manage_email


To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email

On Wed, Oct 7, 2009 at 11:44 PM, Charles Oliver N.
[email protected] wrote:

Sorry about this Yoko. Someone else reported it in JRUBY-4039, and I
just posted about the fix to dev list. I’d appreciate your feedback
there, but I have fixed it on master…

Ok, I’ll add a comment on it when codehaus jira is available to use
again.
As far as I tried using master, implicit type conversion worked well
although “return [x, y, z].to_java(:long)” doesn’t. But this might be
a bug of JRuby Embed, so I’ll find out which one causes this.

-Yoko

  • Java interface:
    include Java::vanilla.Calculable
    package vanilla;
    Object receiver = container.runScriptlet(PathType.CLASSPATH, filename);
    }

I’ve just finished adding part of the Java Integration proposal, the
list.java_send :add, [Java::int, java.lang.Object], 0, ‘foo’

These should provide workarounds for almost all cases where JRuby


To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email


To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email

On Fri, Oct 9, 2009 at 11:23 AM, Yoko H. [email protected] wrote:

Ok, I’ll add a comment on it when codehaus jira is available to use again.
As far as I tried using master, implicit type conversion worked well
although “return [x, y, z].to_java(:long)” doesn’t. But this might be
a bug of JRuby Embed, so I’ll find out which one causes this.

Actually I might suspect a bug in JRuby for that. Please confirm that
it’s a regression, and if so we’ll fix it.

  • Charlie

To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email