3

I'd like to define a superclass in Java, then define a subclass in Ruby, then make instances of that subclass in Java. A little something like this:

// Java superclass
package myPkg;

public class Sup{
  public Sup(){}
  public abstract void foo(String a);
}

--

# Ruby code
include Java
require 'jruby/core_ext'

include_class 'myPkg.Sup'

class RubySub < Java::myPkg.Sup
  def foo( a )
    puts a;
  end
end

RubySub.become_java!
RubySub

--

// Back in Java land
Ruby runtime =  Ruby.newInstance();
IRubyObect ro = runtime.evalScriptlet(theRubyCodeAbove);
Class<Sup> clz = (Class<Sup>) JavaEmbedUtils.rubyToJava(runtime, ro, Class.class);
clz.newInstance().foo("Hey!");

I've tried the above code, but I get an InstantiationException from the newInstance() call. I want to have the class declared in Ruby at runtime, so e.g. running jrubyc to compile the Ruby code to a Java class definition ahead of time is out. What am I doing wrong here?

I've run through the bottom code segment in the debugger, and I'm definitely getting a RubyClass object returned from the evalScriptlet() call. Maybe there's an extra step involved to turn a RubyClass into a Class?


UPDATE: I have a lead -- apparently become_java! doesn't work if the class is a subclass of a Java class. Is there another way I can do this, or am I just boned?

1 Answer 1

3

I've come up with a workaround for now, but it's not pretty.

In brief: I can't return RubySub.become_java! (which is nil, because of JRUBY-6105) or try to return RubySub and convert from a RubyClass to a Class.

Instead, I return RubySub.method(:new), which shows up as a RubyMethod. I can call this, and it creates an IRubyObject which is actually an instance of the subclass. This can be cast to the Java superclass using JavaEmbedUtils.rubyToJava(). Like I said, it's not pretty but it works.

Sign up to request clarification or add additional context in comments.

4 Comments

Interesting... I was referred to your question from my own In my case, I tried your above solution with a class that inherits from VBox (javafx): class Controller < Java::javafx.scene.layout.VBox; end With no luck: #<NameError: no method 'rubyToJava' for arguments (org.jruby.proxy.javafx.scene.layout.VBox$Proxy2) on Java::OrgJrubyJavasupport::JavaEmbedUtils>
The rubyToJava call that I'm making takes 3 arguments -- the runtime (Ruby) instance, the object (IRubyObject), and the target (i.e. Java parent) class. Yours would look like JavaEmbedUtils.rubyToJava(myRubyInterp, theController, VBox.class). I read your question, and it's a shame that framework code is outside your control. Calling getDelcaredMethods() is a terrible, un-ruby-ish way to solve the problem, when they should have used respond_to?.
The third party in this case is java code (which I have no affiliation with, or command of), which is using reflection to see all functions defined in the (now) java-ized version of my class. So in this case what I was hoping for was that ruby methods would automatically be seen in the java-ized version of the code and could be called from the java class. This sounds like it might be a different than what you're trying to do above. Either way I was hoping become_java would do it, like you have it here, but it seems as though it does not.
A quick aside: I had also tried java_signature to do this, but that seems like it has no effect. I'm not sure if it's related to the become_java issue or not... it looks as though there have been other java_signature issues, referenced here. I'm also probably outside of the scope of your post now as well - if so my apologies.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.