Search code examples
javajrubyclassloader

loading JRuby classes from Java by Class.forName


I have following class in Java code:

public class CHRTreeCreator extends IndexCreator { ... }

Instead CHRTreeCreator I want to use diffrent implementation which also extends IndexCreator, but I want to code it in JRuby. The problem is, specific implementation of IndexCreator is chosen based on xml config file:

<creator>dwe.index.tree.chr.CHRTreeCreator</creator>

the code looks like this:

// className is fetched from XML
Class creatorClass = Class.forName(className);
Constructor constructor = creatorClass.getConstructor(new Class[] {  });
creator = (IndexCreator) constructor.newInstance(new Object[] { });

The question is, is it possible to implement it in Ruby, like this:

class MyIndexCreator < IndexCreator
end

and somehow put MyIndexCreator class name into XML config file. How does module - packages mapping work in that case?

If it's not possible to load Ruby classes by Java's Class.forName, how should I solve that issue?


Solution

  • Currently JRuby subclasses are not accessible via Java in this way, although it is planned in some capacity for future implementations (JRuby 1.5 perhaps).

    One option (depending on the API of your class) is to create a delegate:

    public class RubyIndexCreator extends IndexCreator {
      private IndexCreator rubyCreator;
      public RubyIndexCreator() {
        ScriptEngineManager factory = new ScriptEngineManager();
        ScriptEngine engine = factory.getEngineByName("ruby");
        FileReader r = new FileReader("ruby_index_creator.rb");
        try {
          rubyCreator = engine.eval(r);
        }
        finally {
          r.close();
        }
      }
    
      public Object create(String someArg) {
        return rubyCreator.create(someArg);
      }
    }
    

    I've glossed over some opportunities for caching, and also just sketched out managing the file reader, but hopefully you get the picture.

    In this particular example, ruby_index_creator.rb would implement your index creator class, and then return an instance of it - obviously from here you can reference other ruby files, and organize as appropriate:

    class MyIndexer < IndexCreator
     [...]
    end
    MyIndexer.new
    

    That's about it!