Search code examples
javajruby

Access classes defined in a jar file, from within (for instance) JRuby irb?


(Crossposting note: I have asked this question one week ago at the JRuby mailing list, but didn't get any answer yet).

I have a jar file provided by someone else, no access to the source code. The jar file is in lib/other/appl.jar, the class is named Appl, and the package is com.abc.xyz

I would like to instantiate an Appl object from the JRuby irb, jirb_swing_ex.

(Of course my problem applies not only to jirb, but to running JRuby programs in general, but I explain it in the way I'm using it right now, just in case there are some peculiarities in Jirb which need special treatment).

THIS is the way it DOES work:

(1) Invoke jirb by:

java -jar jr/jruby-complete-1.7.27 jb/jirb_swing_ex

(2) Put the directory with the jar file into the load path:

$: << 'lib/other'

(3) Load the jar file

require 'appl.jar'

(4) Import the class

java_import com.abc.xyz.Appl

(5) Create the object

x = Appl.new

As I said, this works, and I can live with it if necessary, but I would prefer a simpler approach:

NOW TO MY QUESTION: Instead of fiddling around with load path and doing a require for the Jar file, I thought I could let Java already include the jar file. This is what I have tried:

java -cp lib/other/appl.jar -jar jr/jruby-complete-1.7.27 jb/jirb_swing_ex

The problem is: How can I get at my object? If I just use the class name com.abc.xyz.Appl, JRuby complains that the class not found (NameError: missing class name).

BTW, I have also tried forward slashes (since I'm on Windows), i.e.

java -cp lib\other\appl.jar -jar jr\jruby-complete-1.7.27 jb\jirb_swing_ex

but the same effect. I had expected that, having appl.jar in my class path, would make the classes available somehow, but I seem to miss something.


Solution

  • Running jirb or jirb_swing with custom class path

    jirb and jirb_swing will use the value of JRUBY_CP environment variable (if present) to extend class path given to Java command line.

    Example with commons-lang3 library taken from my local maven repository, using bash on Linux or macOS:

    $ export JRUBY_CP=${HOME}/.m2/repository/org/apache/commons/commons-lang3/3.4/commons-lang3-3.4.jar
    
    $ jirb
    irb(main):001:0> org.apache.commons.lang3.mutable.MutableBoolean.new
    => #<Java::OrgApacheCommonsLang3Mutable::MutableBoolean:0x7c24b813>
    

    Running JRuby programs with custom class path

    To run a JRuby program that uses a third-party java library, this won't work:

    java -cp lib/other/appl.jar -jar jr/jruby-complete-1.7.27 ...
    

    You must use either -jar or -cp, you can't combine the two.
    From java man page:

    When you use this option [-jar], the JAR file is the source of all user classes, and other user class path settings are ignored.

    In addition, you need to pass the main Java class, which is org.jruby.Main, and that class needs arguments: either a path to a Ruby script, or other command line arguments such as -e 'puts 2+2'.

    So the command line structure is the following:

    # Run script file:
    java -cp path/to/jruby.jar:other/custom.jar org.jruby.Main path/to/script
    # Run simple one-line Ruby program
    java -cp path/to/jruby.jar:other/custom.jar org.jruby.Main -e 'some ruby here'
    

    (on Windows please use ; instead of : as separator)

    Actual example with same commons-lang3 library & OS:

    $ alias myjruby="java -cp ${JRUBY_HOME}/lib/jruby.jar:${HOME}/.m2/repository/org/apache/commons/commons-lang3/3.4/commons-lang3-3.4.jar org.jruby.Main"
    
    # Verifying base jruby code works with that:
    $ myjruby -e 'puts 2+2'
    4
    
    # Now verifying it can use my 3rd-party lib:
    $ myjruby -e 'puts org.apache.commons.lang3.mutable.MutableBoolean.new'
    false