How to get from JRuby a correctly typed ruby imple

2019-03-03 12:00发布

问题:

I'm trying to use JRuby (through the JSR233 interface included in JRuby 1.5) from a Java application to load a ruby implementation of a Java interface.

My sample implementation looks like this:

Interface:

package some.package;
import java.util.List;
public interface ScriptDemoIf {
    int fibonacci(int d);
    List<String> filterLength(List<String> source, int maxlen);
}

Ruby Implementation:

require 'java'
include Java

class ScriptDemo
  java_implements some.package.ScriptDemoIf
  java_signature 'int fibonacci(int d)'
  def fibonacci(d)
    d < 2 ? d : fibonacci(d-1) + fibonacci(d-2)
  end

  java_signature 'List<String> filterLength(List<String> source, int maxlen)'
  def filterLength(source, maxlen)
    source.find_all { |str| str.length <= maxlen }
  end
end

Class loader:

public ScriptDemoIf load(String filename) throws ScriptException {
    ScriptEngine engine = new ScriptEngineManager().getEngineByName("jruby");
    FileReader script = new FileReader(filename);
    try {
        engine.eval(new FileReader(script));
    } catch (FileNotFoundException e) {
        throw new ScriptException("Failed to load " + filename);
    }
    return (ScriptDemoIf) m_engine.eval("ScriptDemo.new");
}

(Obviously the loader is a bit more generic in real life - it doesn't assume that the implementation class name is "ScriptDemo" - this is just for simplicity).

Problem - I get a class cast exception in the last line of the loader - the engine.eval() return a RubyObject type which doesn't cast down nicely to my interface. From stuff I read all over the web I was under the impression that the whole point of use java_implements in the Ruby section was for the interface implementations to be compiled in properly.

What am I doing wrong?

回答1:

It should be, but unfortunately isn't quite wired up that way yet. For now, #java_implements and #java_signature are only used by the jrubyc --java command that creates a Java source file based on the Ruby class. You may want to consider using that for your Ruby integration.

We're aiming for this example to work for both precompiled scripts and runtime-executed scripts in the future. If you instead want this script to work as intended, try using include Java::some.package.ScriptDemoIf instead of java_implements.