JRuby (please use github issues at http://bugs.jruby.org)
  1. JRuby (please use github issues at http://bugs.jruby.org)
  2. JRUBY-6762

How to detect if a Ruby method has been defined using ScriptingContainer

    Details

    • Number of attachments :
      0

      Description

      We are doing something like this:

      import org.jruby.embed.ScriptingContainer;
      import java.util.Arrays;
      
      class MethodsExample {
          pubic void myJavaMethod() {
          }
      
          public static void main(String[] args) {
              System.out.println("Hello world!");
              ScriptingContainer sc = new ScriptingContainer();
              MethodsExample me = new MethodsExample();
      
              Object rubyClass = sc.runScriptlet("Java::MethodsExample");
              sc.put("MethodExample", rubyClass);
              sc.runScriptlet("class MethodsExample ; def my_ruby_method ; puts 'YES!' ; end ; end");
      
              // Expect true
              sc.callMethod(me, "respond_to?" , new Object[]{"my_ruby_method"}, Boolean.class);
              // Want false
              sc.callMethod(me, "respond_to?" , new Object[]{"my_java_method"}, Boolean.class);
              // Want false
              sc.callMethod(me, "respond_to?" , new Object[]{"myJavaMethod"}, Boolean.class);
          }
      }
      

      We want to call the Ruby method only if it is defined on the Ruby side, and ignore it if it is only defined on the Java side.

      Any ideas on how to do this?

        Activity

        Hide
        Charles Oliver Nutter added a comment -

        My first thought would be that the method is not getting defined on the class properly. Can you confirm that a call to the method from the Java side actually works? A la...

        sc.callMethod(me, "my_ruby_method", Boolean.class); // unsure of API here myself)
        

        I know of no reason why reopening a Java class and adding methods would not appear on instances of that method. Obviously it works from Ruby:

        irb(main):001:0> java_import java.util.ArrayList
        => [Java::JavaUtil::ArrayList]
        irb(main):002:0> class ArrayList; def foo; end; end
        => nil
        irb(main):003:0> ArrayList.new.respond_to? :foo
        => true
        
        Show
        Charles Oliver Nutter added a comment - My first thought would be that the method is not getting defined on the class properly. Can you confirm that a call to the method from the Java side actually works? A la... sc.callMethod(me, "my_ruby_method" , Boolean .class); // unsure of API here myself) I know of no reason why reopening a Java class and adding methods would not appear on instances of that method. Obviously it works from Ruby: irb(main):001:0> java_import java.util.ArrayList => [Java::JavaUtil::ArrayList] irb(main):002:0> class ArrayList; def foo; end; end => nil irb(main):003:0> ArrayList.new.respond_to? :foo => true
        Hide
        Yoko Harada added a comment -

        Me, too, don't have clear understanding what you (@Uwe) want to do.

        But, I think this is Ruboto's GSoC related. I guess Uwe and a mentee want this to improve Ruboto's performance?

        Show
        Yoko Harada added a comment - Me, too, don't have clear understanding what you (@Uwe) want to do. But, I think this is Ruboto's GSoC related. I guess Uwe and a mentee want this to improve Ruboto's performance?
        Hide
        Uwe Kubosch added a comment -

        I am working on an example using runScriptlet instead of callMethod. I'll share it as soon as I have it working properly.

        Show
        Uwe Kubosch added a comment - I am working on an example using runScriptlet instead of callMethod. I'll share it as soon as I have it working properly.
        Hide
        Uwe Kubosch added a comment -

        Here is a working example using runScriptlet and global variables:

        import org.jruby.embed.ScriptingContainer;
        
        class MethodsExample {
            public void myJavaMethod(String message) {
                System.out.println("myJavaMethod called: " + message);
            }
        
            public static void main(String[] args) {
                ScriptingContainer sc = new ScriptingContainer();
                MethodsExample me = new MethodsExample();
        
                sc.put("MethodsExample", sc.runScriptlet("Java::MethodsExample"));
                sc.runScriptlet("class MethodsExample ; def my_ruby_method(msg) ; puts \"my_ruby_method called: #{msg}\" ; end ; end");
        
                sc.put("$java_instance", me);
        
                // Should be called since a Ruby method is defined
                if ((Boolean) sc.runScriptlet("MethodsExample.instance_methods(false).include?(:my_ruby_method)")) {
                    sc.put("$ruby_arg", "ruby msg");
                    sc.runScriptlet("$java_instance.my_ruby_method($ruby_arg)");
                }
        
                // Should not be called
                if ((Boolean) sc.runScriptlet("MethodsExample.instance_methods(false).include?(:my_java_method)")) {
                    sc.put("$java_arg", "java msg");
                    sc.runScriptlet("$java_instance.my_java_method($java_arg)");
                }
        
                // Should not be called
                if ((Boolean) sc.runScriptlet("MethodsExample.instance_methods(false).include?(:myJavaMethod)")) {
                    sc.put("$java_arg", "java msg");
                    sc.runScriptlet("$java_instance.myJavaMethod($java_arg)");
                }
            }
        }
        

        I would love to have a way to do this without global variables. Also, using runScriptlet seems overkill for calling a method. I think using callMethod would be better.

        What do you think?

        Show
        Uwe Kubosch added a comment - Here is a working example using runScriptlet and global variables: import org.jruby.embed.ScriptingContainer; class MethodsExample { public void myJavaMethod(String message) { System.out.println("myJavaMethod called: " + message); } public static void main(String[] args) { ScriptingContainer sc = new ScriptingContainer(); MethodsExample me = new MethodsExample(); sc.put("MethodsExample", sc.runScriptlet("Java::MethodsExample")); sc.runScriptlet("class MethodsExample ; def my_ruby_method(msg) ; puts \"my_ruby_method called: #{msg}\" ; end ; end"); sc.put("$java_instance", me); // Should be called since a Ruby method is defined if ((Boolean) sc.runScriptlet("MethodsExample.instance_methods(false).include?(:my_ruby_method)")) { sc.put("$ruby_arg", "ruby msg"); sc.runScriptlet("$java_instance.my_ruby_method($ruby_arg)"); } // Should not be called if ((Boolean) sc.runScriptlet("MethodsExample.instance_methods(false).include?(:my_java_method)")) { sc.put("$java_arg", "java msg"); sc.runScriptlet("$java_instance.my_java_method($java_arg)"); } // Should not be called if ((Boolean) sc.runScriptlet("MethodsExample.instance_methods(false).include?(:myJavaMethod)")) { sc.put("$java_arg", "java msg"); sc.runScriptlet("$java_instance.myJavaMethod($java_arg)"); } } } I would love to have a way to do this without global variables. Also, using runScriptlet seems overkill for calling a method. I think using callMethod would be better. What do you think?
        Hide
        Uwe Kubosch added a comment -

        This issue is fixed by JRUBY-6785.

        Show
        Uwe Kubosch added a comment - This issue is fixed by JRUBY-6785 .

          People

          • Assignee:
            Unassigned
            Reporter:
            Uwe Kubosch
          • Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved: