views:

243

answers:

3

Hello,

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?

A: 

As an alternative, perhaps you could take advantage of Ruby's Open Classes and modify the behaviour of CHRTreeCreator directly (as opposed to sub-classing).

Rob
Thanks Rob, that solution can work somehow in my case (and I did go that way for now), but I would prefer not to monkey-patch Java classes. There should be some general way to load Ruby classes with .forName method, right?
Marek K
A: 

How about using ruby eval:

C:\>jirb
irb(main):001:0> require 'java'
=> false
irb(main):002:0> class MyDate < Java::JavaUtil::Date
irb(main):003:1> def my_method;puts "hi there";end
irb(main):004:1> end
=> nil
irb(main):005:0>
irb(main):006:0* c = "MyDate"
=> "MyDate"
irb(main):007:0> obj = eval("#{c}.new")
=> #<MyDate:0xd2efa1>
irb(main):008:0> obj.my_method
hi there
=> nil
irb(main):009:0>
Rob
+5  A: 

Hi Marek, 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!

RealJenius