Details
-
Type:
Bug
-
Status:
Resolved
-
Priority:
Major
-
Resolution: Fixed
-
Affects Version/s: JRuby 1.6.7, JRuby 1.7.0.pre1
-
Fix Version/s: JRuby 1.7.0.pre2
-
Component/s: Java Integration
-
Labels:None
-
Environment:OS X 10.7.4 + Apple Java 1.6.0_33-b03-424-11M3720
Android 2.3 and 4.0
-
Number of attachments :
Description
This is causing us to use runScriptlet in the Ruboto internals, but the behavior is the same using OS X + Apple Java 6.
We reopen a Java class to define Ruby methods on it, and then call these methods directly from Java. Here is an example:
import org.jruby.embed.ScriptingContainer;
class ReopenJavaClass {
public ReopenJavaClass() {}
public static void main(String[] args) throws Exception {
ScriptingContainer sc = new ScriptingContainer(org.jruby.embed.LocalContextScope.SINGLETON,
org.jruby.embed.LocalVariableBehavior.TRANSIENT);
sc.put("ReopenJavaClass", sc.runScriptlet("Java::ReopenJavaClass"));
sc.runScriptlet("class ReopenJavaClass ; def ruby_method ; puts 'Success!' ; end ; end");
sc.callMethod(new ReopenJavaClass(), "ruby_method");
}
}
When we run this we get the following exception:
$ javac -cp .:../jruby/dist/jruby-complete-1.7.0.preview2.dev.jar -d tmp ReopenJavaClass.java $ java -cp .:../jruby/dist/jruby-complete-1.7.0.preview2.dev.jar ReopenJavaClass NoMethodError: undefined method `ruby_method' for main:Object Exception in thread "main" org.jruby.embed.InvokeFailedException: (NoMethodError) undefined method `ruby_method' for main:Object at org.jruby.embed.internal.EmbedRubyObjectAdapterImpl.call(EmbedRubyObjectAdapterImpl.java:296) at org.jruby.embed.internal.EmbedRubyObjectAdapterImpl.callMethod(EmbedRubyObjectAdapterImpl.java:241) at org.jruby.embed.ScriptingContainer.callMethod(ScriptingContainer.java:1367) at ReopenJavaClass.main(ReopenJavaClass.java:11) Caused by: org.jruby.exceptions.RaiseException: (NoMethodError) undefined method `ruby_method' for main:Object
Are we using callMethods wrongly? Any help on this would be absolutely great!
I looked through the JRuby code and found that receiver must be an instance of IRubyObject. Neither the method signature nor the method documentation hints at this.
Using JavaEmbedUtils I changed the example to this:
import org.jruby.embed.ScriptingContainer; import org.jruby.javasupport.JavaEmbedUtils; class JRUBY_6785 { public JRUBY_6785() {} public static void main(String[] args) throws Exception { ScriptingContainer sc = new ScriptingContainer(); sc.put("JRUBY_6785", sc.runScriptlet("Java::JRUBY_6785")); sc.runScriptlet("class JRUBY_6785 ; def ruby_method ; puts 'Success!' ; end ; end"); sc.callMethod(JavaEmbedUtils.javaToRuby(sc.getProvider().getRuntime(), new JRUBY_6785()), "ruby_method"); } }This seems to work. Woohoo!
Is this the right/best way to do it?