загрузка классов JRuby из Java по Class.forName

У меня есть следующий класс в коде Java:

public class CHRTreeCreator extends IndexCreator { ... }

Вместо этого CHRTreeCreator я хочу использовать другую реализацию, которая также расширяет IndexCreator, но я хочу закодировать ее в JRuby. Проблема в том, что конкретная реализация IndexCreator выбирается на основе файла конфигурации xml:

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

код выглядит так:

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

Вопрос в том, можно ли это реализовать на Ruby, вот так:

class MyIndexCreator < IndexCreator
end

и каким-то образом поместите имя класса MyIndexCreator в файл конфигурации XML. Как в этом случае работает сопоставление модулей и пакетов?

Если невозможно загрузить классы Ruby с помощью Java Class.forName, как мне решить эту проблему?


person Marek K    schedule 04.11.2009    source источник


Ответы (3)


В настоящее время подклассы JRuby недоступны через Java таким образом, хотя это планируется в некоторой степени для будущих реализаций (возможно, JRuby 1.5).

Один из вариантов (в зависимости от API вашего класса) — создать делегата:

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);
  }
}

Я упустил некоторые возможности кэширования, а также только набросал управление программой чтения файлов, но, надеюсь, вы поняли картину.

В этом конкретном примере ruby_index_creator.rb будет реализовывать ваш класс создателя индекса, а затем возвращать его экземпляр - очевидно, отсюда вы можете ссылаться на другие файлы ruby ​​​​и организовывать соответствующим образом:

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

Вот об этом!

person Community    schedule 11.11.2009

В качестве альтернативы, возможно, вы могли бы воспользоваться преимуществами открытых классов Ruby и напрямую изменить поведение CHRTreeCreator (в отличие от подклассов).

person Robert Brown    schedule 05.11.2009
comment
Спасибо, Роб, это решение может работать как-то в моем случае (и я действительно пошел по этому пути сейчас), но я бы предпочел не исправлять Java-классы обезьяны. Должен же быть какой-то общий способ загрузки классов Ruby с помощью метода .forName, верно? - person Marek K; 08.11.2009

Как насчет использования 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>
person Robert Brown    schedule 08.11.2009