Getting started with become_java!

I’m having problems getting the Java <-> Ruby integration to work in
jRuby
1.4.0 and signed up to the list in order to tap into the more
experienced
crowd.

When I try to cast a new instance of the jruby-generated java object
into a
Java interface which that object implements I’m getting
ClassCaseException.
If anyone could point out what I’m doing wrong I’d be extremely
grateful.

The following test case should work unless I’ve misunderstood the
examples
Charles and Vladimir have posted elsewhere on the web:

package org.test;
import javax.script.ScriptEngineManager;

public class Runner {

public static interface Interface { }
public static Class<? extends Interface> RClass;

static String getRubySource() {
    return
        "  require 'jruby/core_ext'                         \n" +
        "  class RubyClass                                  \n" +
        "    include org.test.Runner::Interface             \n" +
        "  end                                              \n" +
        "  org.test.Runner.RClass = RubyClass.become_java!  \n";
}

public static void main(String[] args) throws Exception {
    new ScriptEngineManager()
        .getEngineByName("jruby")
        .eval(getRubySource());

    /* Will throw a ClassCastException, why?  */
    Interface object = RClass.newInstance();
}

}

On Thu, Feb 4, 2010 at 8:19 PM, Jonas T. [email protected]
wrote:

static String getRubySource() {
    return
        "  require 'jruby/core_ext'                         \n" +
        "  class RubyClass                                  \n" +
        "    include org.test.Runner::Interface             \n" +
        "  end                                              \n" +
        "  org.test.Runner.RClass = RubyClass.become_java!  \n";
}

You need to return an instance of RubyClass object.

org.test.Runner.RClass.new

instead of org.test.Runner.RClass = RubyClass.become_java! of the last
line.
Give this a try.
Samples at
http://kenai.com/projects/jruby/pages/RedBridgeExamples#Interface_Implementation
will help you to get this work.

Even though you keep getting the ClassCastException, come back to this
list since that should be a bug.

-Yoko


To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email

Yoko H. wrote:

org.test.Runner.RClass.new

instead of org.test.Runner.RClass = RubyClass.become_java! of the last line.
Give this a try.

Thanks Yoko, however does your suggestion not change the semantics of
the stanza in that an instance is returned instead of a class?

Could you also explain what you mean by “need to return an instance”?

It was my understanding that the become_java! method added to the ruby
Class object should explicitly allow the Java-side to operate on Ruby
classes and not class instances. I.e. to allow instantiating Ruby
classes the same as way as you do pure Java classes.

Samples at http://kenai.com/projects/jruby/pages/RedBridgeExamples#Interface_Implementation
will help you to get this work.

Unfortunately I found no example nor page on that site which discuss the
new Class#become_java! method, a method which is added to the Class
object when jruby/core_ext is loaded.

The method does not have any documentation, rspecs nor junit tests (that
I could find) which would specify how the function is supposed to
behave. That’s the underlying reason to why I posted the initial mail to
the list in the first place, to try get some clarity about this
function.

New discovery:
I just stumbled upon #4271 (http://jira.codehaus.org/browse/JRUBY-4271)
which may be what is causing the problem I’m seeing.

My error message when running the sample is:

Exception in thread “main” java.lang.ClassCastException:
ruby.RubyClass cannot be cast to org.test2.Runner$Interface
at org.test2.Runner.main(Runner.java:24)

If the problem I’m facing is due to the reported bug, should I consider
“become_java!” as broken in 1.4.0 or is there a work-around which can be
used for the released version without patching the jRuby library?


To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email

On Fri, Feb 5, 2010 at 3:48 PM, Jonas T. [email protected]
wrote:

Could you also explain what you mean by “need to return an instance”?

It was my understanding that the become_java! method added to the ruby Class
object should explicitly allow the Java-side to operate on Ruby classes and
not class instances. I.e. to allow instantiating Ruby classes the same as
way as you do pure Java classes.

Ah, I misunderstood what you wanted to do. Forget “need to return
instance.”

could find) which would specify how the function is supposed to behave.
Exception in thread “main” java.lang.ClassCastException:
ruby.RubyClass cannot be cast to org.test2.Runner$Interface
at org.test2.Runner.main(Runner.java:24)

The issue you found might be the reason, but I recommend making sure
what Java class was generated. Like in this exception, generated class
has “ruby” in its package name. To see what kind of class is
generated, you can use javap command. For example, if you specify the
directory for the generated class,

RubyClass.become_java!(“/Users/yoko/projects/samples”)

then JRuby creates ruby directory in /Users/yoko/projects/samples and
*.class, RubyClass.class in your case, is located under ruby. So,
when you try below:

cd /Users/yoko/projects/samples
javap -classpath . ruby.RubyClass

you can see the fully qualified class name, constructor, other method
names and signatures.

Perhaps, “5. Generate Real Java Classes from Ruby” of
http://www.engineyard.com/blog/2009/5-things-to-look-for-in-jruby-1-4/
is a good info.

-Yoko


To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email

Yoko H. wrote:

You need to return an instance of RubyClass object.
what Java class was generated. Like in this exception, generated class
has “ruby” in its package name. To see what kind of class is
generated, you can use javap command. For example, if you specify the
directory for the generated class,

RubyClass.become_java!(“/Users/yoko/projects/samples”)

Interesting, I didn’t know that it was possible to get the compiled
class serialized to disk “out of the box”. Useful indeed!

Anyhow, it does indeed seem that not a trace of the implemented java
interface exists in the byte code. The following is the output from
javap:

$ javap -classpath . ruby.RubyClass
public class ruby.RubyClass extends org.jruby.RubyObject{
public static void clinit(org.jruby.Ruby, org.jruby.RubyClass);
public ruby.RubyClass(org.jruby.Ruby, org.jruby.RubyClass);
public ruby.RubyClass();
public org.jruby.runtime.builtin.IRubyObject
equal_equal_equal(org.jruby.runtime.builtin.IRubyObject[]);
public org.jruby.runtime.builtin.IRubyObject java_class();
public org.jruby.runtime.builtin.IRubyObject
_jcreate_meta_b(org.jruby.runtime.builtin.IRubyObject[]);
public org.jruby.runtime.builtin.IRubyObject
old_eqq(org.jruby.runtime.builtin.IRubyObject[]);
public org.jruby.runtime.builtin.IRubyObject
_jcreate_b(org.jruby.runtime.builtin.IRubyObject[]);
}

Using verbose didn’t show a reference either, nor did the unix
strings-command. Unless you have some other idea or angle I could try to
pin-point the problem, it looks like I’ll have to use the 1.5
development stream for java-ruby integration. Unfortunately that
prevents me from using this (cool/useful) mechanism in production for
obvious reasons :o/

Perhaps, “5. Generate Real Java Classes from Ruby” of
http://www.engineyard.com/blog/2009/5-things-to-look-for-in-jruby-1-4/
is a good info.

That article was where I first heard about ruby2java and become_java. I
initially tried ruby2java but didn’t get it to work with jRuby 1.4, so
empirical evidence led me to believe that it might have been replaced by
the “live” become_java variant instead. This feature was indeed the most
interesting thing with the 1.4 release (aside from the 1.8.7 support
that is).


To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email