JRuby integration problem

Hello all,
Sorry if this is a (too) long message.

First a little background on my problem…

I have some java code that I’d like to wrap with jruby (eventually so I
can
use it in a jruby on rails app, but that’s not relevant at the moment).
Essentially, I am trying to do the following

I ‘require java’
I iterate across all the jar files I should need in the lib directory of
my
project with ‘Dir[“lib/*.jar”].each { |jar| require jar }’

I ‘java_import my.package.and.className’

however, when I try to use my class, it calls out to a delegate class to
take care of some initialization/singleton stuff (I didn’t write it, so
don’t blame me). The problem is I wind up with this error
NativeException: java.lang.RuntimeException: Unexpected
ClassNotFoundException looking up class ‘org/jruby/Main’

I can only guess that the init code is doing something seriously funky,
which is why JRuby can’t find it’s own running class (assuming I’m
reading
the error correctly). Any ideas for dealing with this are greatly
appreciated.

Now the immediate problem…

So far, I’ve tried setting the log4j level to debug, so I could get a
better idea of where in the java code, the errors are actually coming
from.
That has proven to be more difficult than I imagined.
I used this code to set the log level, and print it back out, so I know
it
at least thinks the setting took

org.apache.log4j.LogManager.getLogger(“my.package.className.class”).setLevel(org.apache.log4j.Level.toLevel(“DEBUG”))
puts "Log level is "+
org.apache.log4j.LogManager.getLogger(“my.package.className.class”).getEffectiveLevel.toString
Indeed, that does print out ‘DEBUG’, however, I’m still only seeing log
messages from my java code at INFO level.

I also threw a log4j.properties file in the directory and load it as
file = File.new(“log4j.properties”);
PropertyConfigurator.configure(file.toURL());
logger = Logger.getLogger(“java_integ_test.rb”);
logger.debug(“Test of debug msg”);

and it does seem to print out the debug message. I use that config file
to
set the root logger to DEBUG level

log4j.rootLogger=DEBUG, stdout
log4j.logger.com=DEBUG

However, I’m still not getting any debug messages from my java code
(only
the ruby script itself)

So, my two questions are.

  1. how the @#$% can I get the logger to run in debug for my java code
  2. Any idea on what the first error actually means?

I strongly suspect that if I can get 1 answered, then 2 will follow
easily.

I doubt that it matters, but I’m running jruby-1.6.7 [
darwin-x86_64-java ]
on OSX. The behavior is the same for both Mountain Lion with Java 1.7,
and
Lion with Java 1.6.

Thanks for reading this far,
Mat

Mathew -

I think your problem is the backslash in the argument to Dir[]. Why do
you have it there? I think you only want:

Dir[“lib/*.jar”]

  • Keith


Keith R. Bennett

I have corrected that, but the behavior appears to be unchanged.

As a test, I created a new lib directory, and changed my classpath code
to
Dir["./lib2/*.jar"].each { |jar|
require jar
puts jar.inspect
}

Now, if I run my jruby with -d, I see these errors(?), even though the
file
is there, and being seen.

java.lang.ClassNotFoundException: lib2.Slf4j-log4j12-1.6.4Service
at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
at org.jruby.util.JRubyClassLoader.findClass(JRubyClassLoader.java:86)
at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:247)
at org.jruby.javasupport.JavaSupport.loadJavaClass(JavaSupport.java:136)
at
org.jruby.runtime.load.LoadService$ExtensionSearcher.trySearch(LoadService.java:597)
at
org.jruby.runtime.load.LoadService.findFileForLoad(LoadService.java:283)
at org.jruby.runtime.load.LoadService.smartLoad(LoadService.java:330)
at org.jruby.runtime.load.LoadService.require(LoadService.java:379)
at
org.jruby.runtime.load.LoadService.lockAndRequire(LoadService.java:304)
at org.jruby.RubyKernel.requireCommon(RubyKernel.java:1050)
at org.jruby.RubyKernel.require(RubyKernel.java:1033)
at
org.jruby.RubyKernel$s$1$0$require.call(RubyKernel$s$1$0$require.gen:65535)
at
org.jruby.internal.runtime.methods.JavaMethod$JavaMethodOneOrNBlock.call(JavaMethod.java:319)
at
org.jruby.runtime.callsite.CachingCallSite.call(CachingCallSite.java:167)
at $dot.java_test.block_0$RUBY$file(./java_test.rb:9)
at
$dot$java_test$block_0$RUBY$file.call($dot$java_test$block_0$RUBY$file:65535)
at org.jruby.runtime.CompiledBlock.yield(CompiledBlock.java:112)
at org.jruby.runtime.CompiledBlock.yield(CompiledBlock.java:95)
at org.jruby.runtime.Block.yield(Block.java:130)
at org.jruby.RubyArray.eachCommon(RubyArray.java:1608)
at org.jruby.RubyArray.each(RubyArray.java:1615)
at org.jruby.RubyArray$i$0$0$each.call(RubyArray$i$0$0$each.gen:65535)
at
org.jruby.runtime.callsite.CachingCallSite.cacheAndCall(CachingCallSite.java:302)
at
org.jruby.runtime.callsite.CachingCallSite.callBlock(CachingCallSite.java:144)
at
org.jruby.runtime.callsite.CachingCallSite.callIter(CachingCallSite.java:153)
at $dot.java_test.file(./java_test.rb:8)
at $dot.java_test.load(./java_test.rb)
at org.jruby.Ruby.runScript(Ruby.java:697)
at org.jruby.Ruby.runScript(Ruby.java:690)
at org.jruby.Ruby.runNormally(Ruby.java:597)
at org.jruby.Ruby.runFromMain(Ruby.java:446)
at org.jruby.Main.doRunFromMain(Main.java:369)
at org.jruby.Main.internalRun(Main.java:258)
at org.jruby.Main.run(Main.java:224)
at org.jruby.Main.run(Main.java:208)
at org.jruby.Main.main(Main.java:188)
“./lib2/slf4j-log4j12-1.6.4.jar”

The last line shows that the script could see the jar file. I get this
error for each jar file I have in my new lib2 directory. I’m unsure if
this is a real error, if my jruby install is mucked up.

Mat

Why’s it looking for a class that starts with lib2 as the main package -
lib2.Slf4j-log4j12-1.6.4Service

Try using an absolute path. I am using this in my rails application and
it
seems to be fine with the jars I have in place -

Dir["#{File.dirname(FILE)}/…/lib/jars/*.jar"].each do |jar|
require jar
end

FWIW, I ended up using a checkout from the repository and doing a local
JRuby build and setting it in the PATH.

Can you give a full trace for the error? The bigger the better.

Good point.

I reinstalled jruby through rvm (it’s now 1.6.4 as the default version).
I
changed my code based off of what you have below.
On the upside, those ‘errors’ are now gone from the startup, but the end
result is still the same (same error as before
NativeException: java.lang.RuntimeException: Unexpected
ClassNotFoundException looking up class ‘org/jruby/Main’
(root) at ./java_test.rb:28 )

Also, I don’t know if it matters, but when I added a ‘puts jar.inspect’
in
the classpath code, it’s still printing as relative.
“./lib/xercesImpl-2.9.1.jar”
“./lib/xml-apis-1.3.04.jar”

I hardcoded the path, to the full path to the lib dir, and now they are
showing with their full paths, but no real difference in behavior.

I feel like we’re cutting down on the noise around the real problem, but
so
far, it’s still I’m still flummoxed.

Thanks
Mat

Your jruby.jar is in the CLASSPATH, right?

I’m not getting any stack traces now. The sum total of the error (when
running with -d is the one shown below).
NativeException: java.lang.RuntimeException: Unexpected
ClassNotFoundException looking up class ‘org/jruby/Main’
(root) at ./java_test.rb:28 )

Also, I copied the jruby.jar to the lib dir (just to be on the safe
side),
where all the other jars are, and that didn’t seem to make any
difference
in behavior.

Mat

On Mon, Sep 10, 2012 at 11:14 AM, mathew duafala [email protected]
wrote:

NativeException: java.lang.RuntimeException: Unexpected
ClassNotFoundException looking up class ‘org/jruby/Main’

this error I saw when I do something like
$ java -cp
…/…/…/nexus/lib/slf4j-api-1.6.4.jar:~/.m2/repository/org/jruby/jruby-complete/1.7.0.preview2/jruby-complete-1.7.0.preview2.jar
org.jruby.Main -e “puts 123”
Exception in thread “main” java.lang.NoClassDefFoundError:
org/jruby/Main
Caused by: java.lang.ClassNotFoundException: org.jruby.Main

but
$ java -cp
~/.m2/repository/org/jruby/jruby-complete/1.7.0.preview2/jruby-complete-1.7.0.preview2.jar:…/…/…/nexus/lib/slf4j-api-1.6.4.jar
org.jruby.Main -e "puts 123"123

since read you both were talking about CLASSPATH - make sure jruby is
FIRST on the classpath.

about the require and the absolute path - I usually write
p require jar
as debug to see if my jar is loaded.

  • Kristian

Holy Cow, it finally works with this command!

java -cp ./lib/jruby-complete-1.6.7.2.jar org.jruby.Main -S
./java_test.rb

I’m not sure I understand why it needed this specific invocation.

I still don’t understand why the log4j stuff didn’t work, but I’m ok
with
that at the moment.

Thanks for you’re help everyone.

Mat

Hopefully you’ll get an answer from an expert. I’ve personally never
been
able to use debug mode with JRuby.

But in any case, don’t let the jruby.jar be added more than once. I
guess
the regular Java rules must apply.

I have set jruby.jar in my CLASSPATH so that I don’t have to bother with
it. Other jars get loaded in the application as and when another
required.

For your log4j, send another email specifically about that. You might
have
a point there.

I guess that is my personal way of using jruby-complete :slight_smile: - I never
used rvm so can not help you there.

you can have a bit shorted :slight_smile:

java -jar ./lib/jruby-complete-1.6.7.2.jar ./java_test.rb

just do not require ‘jruby.jar’ as Singh wrote.

if you provide the java_test.rb as gist or pastebin and the list of
jars in ./lib/ then I will look into why the ‘jruby’ invoker did not
work :wink:

  • Kristian

Strange…I thought 1.6.7 is the default version installed by rvm.

rvm is great; I highly recommend using it when working with JRuby
because it saves you from having to do all that special stuff, such as
saying jruby instead of ruby, and using jruby -S rake instead of just
rake.

I’d suggest doing:

rvm install jruby-1.6.7

…and then make an alias for it for easier use, and for easier
upgrading to future versions:

rvm alias create jruby jruby-1.6.7

You can make it the default for each new shell like this:

rvm --default jruby

Then you should be able to run your code more easily, such as:

ruby java_test.rb

You shouldn’t need the “./” because you’re not running it as a Unix
command, you’re just passing the filespec of the script to the JRuby
interpreter.

Also, regarding the log4j problem, I’d examine your configuration to see
if something may be wrong. As Pradeep noticed, this:

java.lang.ClassNotFoundException: lib2.Slf4j-log4j12-1.6.4Service

implies that the program is trying to use the class
“Slf4j-log4j12-1.6.4Service” in the package “lib2”.

Are you maybe specifying a filespec instead of a class in the
configuration?

  • Keith


Keith R. Bennett

just one last thought (hope these many emails are not does not annoy
you).

why not using

to manage you jar files. it will take care of loading the jars.

  • Kristian