Unable to access jar dependencies from JRuby gem

2019-08-05 02:15发布

I have created a gem on my local system for text mining which relies on external Java libraries for classification tasks. I'm trying to harness the power of Java through JRuby here. Directory structure is as follows:

- classifier/
 * classifier.gemspec
 * Gemfile
 * Gemfile.lock
 * lib/
     * classifier/
         * version.rb
         * sample_classifier.rb
     * classifier.rb
     * java/
         * sample_lib.jar
         * another_sample_lib.jar
         * yet_another_sample_lib.jar
 * Rakefile

I'm loading these jars in lib/classifier.rb as

Dir["java/*.jar"].each{|jar| require jar}

I have added this gem to a Git repository and referenced it in the Gemfile of my Rails 3.0.9 project. However, my sample_classifier.rb fails to locate any classes 'import'ed from any of the jars under lib/java.

Things work if I copy lib/java to my Rails application

lib/ directory

and add the following in sample_classifier.rb:

Dir["lib/java/*.jar"].each{|jar| require jar}

However, I don't think it's a good practice to spill the gem's dependencies in my Rails app. Is there a better way to achieve this? I looked around for bundling jar files with a gem but I found results for exactly the opposite i.e. bundling gems within a jar file. Can I add these jars to Rails' config.autoload_path or similar to load them when the application starts? Is it a good practice to bundle jar dependencies with the gem?

I'm sure there's a cleaner way to do this.

2条回答
再贱就再见
2楼-- · 2019-08-05 03:11

Might I suggest that managing your Jars with LockJar would be easier. Just install the gem

gem install lock_jar

Create a Jarfile

Create a Jarfile that contains a list of your Jar dependencies:

jar "com.tobedevoured:example1:0.0.1"
jar "com.tobedevoured:example2:0.0.2"
jar "com.tobedevoured:example3:0.0.3"

The simplest jar notation is groupId:artifactId:version. Other supported variations are groupId:artifactId:type:version and groupId:artifactId:type:classifier:version.

Generating a Jarfile.lock

The transitive dependencies are resolved, download, and generate to a Jarfile.lock with the command line:

lockjar lock

(You can also run it from Ruby as LockJar.lock)

Accessing your Jars

The Jarfile.lock contains all the Jar dependency information. Now you can load your jars from the Jarfile.lock to the classpath with:

LockJar.load

When packaging with a Gem, you will need to ensure the Jars from Jarfile.lock have been downloaded with:

LockJar.install

Make sure you request the Jarfile.lock is relative to the Gem's installed dir. Here is an example helper:

module Example
  def self.installHelper
    # get jarfile relative the gem dir from lib/example.rb
    lockfile = File.expand_path( "../../Jarfile.lock", __FILE__ ) 

    LockJar.install( :lockfile => lockfile )
  end

  def self.loadHelper
    # get jarfile relative the gem dir from lib/example.rb
    lockfile = File.expand_path( "../../Jarfile.lock", __FILE__ ) 

    LockJar.load( :lockfile => lockfile )
  end
end

You can also setup your Gem to download the Jar dependencies when the Gem installs, removing the need to call LockJar.install.

查看更多
Root(大扎)
3楼-- · 2019-08-05 03:19

Use absolute paths like so:

jars_dir = File.join(File.dirname(__FILE__), 'java')
for jar in Dir["#{jars_dir}/*.jar"]
  require jar
end
查看更多
登录 后发表回答