Using warbler with jbundler excludes JRuby #261

Closed
hadronzoo opened this Issue Apr 30, 2014 · 6 comments

Comments

Projects
None yet
2 participants
Contributor

hadronzoo commented Apr 30, 2014

I'm having the same issue mentioned by @timuckun on the jruby-user mailing list. When using warbler with jbundler to create a standalone executable, the resulting JAR appears to be missing JRuby. Starting the JAR yields the error:

error: java.lang.ClassNotFoundException: org.jruby.embed.ScriptingContainer

If I include jruby-complete in the jbundler Jarfile, the application will run but periodically throw java.lang.NoClassDefFoundError exceptions, being unable to find JRuby classes like org/jruby/embed/variable/Argv.

Why would warbler be excluding JRuby from packaged JARs? @jkutner @mkristian

hadronzoo changed the title from Using warbler with jbundler appears to exclude JRuby to Using warbler with jbundler excludes JRuby Apr 30, 2014

Owner

mkristian commented May 1, 2014

@hadronzoo next version of jbundler will use the "dependencies" from jruby itself to put it into the mix of jar dependencies to be resolved (more like "hard coding jar org.jruby:jruby into the Jarfile"). so warbler with jbundler will handle the jruby-jars differently. well, missing the whole jruby in the executable jar is quite a big miss ;)

Contributor

hadronzoo commented May 1, 2014

@mkristian When I include jruby-complete, I can resolve most of the startup issues, but it still appears that the JRuby runtime classes are not being imported properly, even though they're on the classpath. I can manually import individual classes in an ad-hoc attempt to eliminate NoClassDefFoundError exceptions, but is there a way to import the entire JRuby runtime and make it available to my application? Most of the exceptions appear to occur when JRuby needs to perform reflection on values returned from Java libraries.

Owner

mkristian commented May 1, 2014

the executable jar starts up and run ruby code until it reaches objects from other java libraries. are those libraries part of the Jarfile ?

what do you mean with import individual classes ?

are just running "java -jar my.jar" ?

sounds like classloader issue ;)

Contributor

hadronzoo commented May 1, 2014

Yes, all of the libraries are part of the Jarfile, I am running java -jar my.jar, and it does sound like a classloader issue with JRuby's runtime.

When executing the application with JRuby (not packaged as a standalone Jar), it runs without exception, thanks to jbundler downloading all of the required Jar dependencies. When packaged as a Jar, exceptions seem to occur because JRuby classes cannot be found—as if parts of the JRuby runtime are not imported. The other libraries will load and run without issue until they return something that appears to require JRuby reflection. Here's an example that occurs during a shutdown hook:

error: org.jruby.embed.EvalFailedException: java.lang.NoClassDefFoundError: org/jruby/embed/variable/Argv
Exception in thread "Thread-6" java.lang.NoClassDefFoundError: org/jruby/util/ConvertDouble
    at org.jruby.RubyNumeric$ByteListCaller19.yield(RubyNumeric.java:387)
    at org.jruby.RubyNumeric.str2fnumCommon(RubyNumeric.java:364)
    at org.jruby.RubyNumeric.str2fnum19(RubyNumeric.java:358)
    at org.jruby.RubyString.to_f19(RubyString.java:4565)
    at org.jruby.RubyString$INVOKER$i$0$0$to_f19.call(RubyString$INVOKER$i$0$0$to_f19.gen)
    at org.jruby.runtime.callsite.CachingCallSite.cacheAndCall(CachingCallSite.java:306)
    at org.jruby.runtime.callsite.CachingCallSite.call(CachingCallSite.java:136)
    at org.jruby.ast.CallNoArgNode.interpret(CallNoArgNode.java:60)
    at org.jruby.ast.CallOneArgFixnumNode.interpret(CallOneArgFixnumNode.java:59)
    at org.jruby.ast.LocalAsgnNode.interpret(LocalAsgnNode.java:123)
    at org.jruby.ast.NewlineNode.interpret(NewlineNode.java:105)
    at org.jruby.ast.BlockNode.interpret(BlockNode.java:71)
    at org.jruby.evaluator.ASTInterpreter.INTERPRET_METHOD(ASTInterpreter.java:74)
    at org.jruby.internal.runtime.methods.InterpretedMethod.call(InterpretedMethod.java:139)
    at org.jruby.internal.runtime.methods.DefaultMethod.call(DefaultMethod.java:182)
    at org.jruby.runtime.callsite.CachingCallSite.cacheAndCall(CachingCallSite.java:306)
    at org.jruby.runtime.callsite.CachingCallSite.call(CachingCallSite.java:136)
    at org.jruby.ast.VCallNode.interpret(VCallNode.java:88)
    at org.jruby.ast.NewlineNode.interpret(NewlineNode.java:105)
    at org.jruby.ast.BlockNode.interpret(BlockNode.java:71)
    at org.jruby.ast.IfNode.interpret(IfNode.java:116)
    at org.jruby.ast.NewlineNode.interpret(NewlineNode.java:105)
    at org.jruby.ast.BlockNode.interpret(BlockNode.java:71)
    at org.jruby.evaluator.ASTInterpreter.INTERPRET_METHOD(ASTInterpreter.java:74)
    at org.jruby.internal.runtime.methods.InterpretedMethod.call(InterpretedMethod.java:139)
    at org.jruby.internal.runtime.methods.DefaultMethod.call(DefaultMethod.java:182)
    at org.jruby.runtime.callsite.CachingCallSite.cacheAndCall(CachingCallSite.java:306)
    at org.jruby.runtime.callsite.CachingCallSite.call(CachingCallSite.java:136)
    at org.jruby.ast.VCallNode.interpret(VCallNode.java:88)
    at org.jruby.ast.IfNode.interpret(IfNode.java:116)
    at org.jruby.ast.NewlineNode.interpret(NewlineNode.java:105)
    at org.jruby.ast.BlockNode.interpret(BlockNode.java:71)
    at org.jruby.evaluator.ASTInterpreter.INTERPRET_METHOD(ASTInterpreter.java:74)
    at org.jruby.internal.runtime.methods.InterpretedMethod.call(InterpretedMethod.java:139)
    at org.jruby.internal.runtime.methods.DefaultMethod.call(DefaultMethod.java:182)
    at org.jruby.runtime.callsite.CachingCallSite.cacheAndCall(CachingCallSite.java:306)
    at org.jruby.runtime.callsite.CachingCallSite.call(CachingCallSite.java:136)
    at org.jruby.ast.CallNoArgNode.interpret(CallNoArgNode.java:60)
    at org.jruby.ast.NewlineNode.interpret(NewlineNode.java:105)
    at org.jruby.evaluator.ASTInterpreter.INTERPRET_BLOCK(ASTInterpreter.java:112)
    at org.jruby.runtime.Interpreted19Block.evalBlockBody(Interpreted19Block.java:206)
    at org.jruby.runtime.Interpreted19Block.yield(Interpreted19Block.java:194)
    at org.jruby.runtime.Interpreted19Block.call(Interpreted19Block.java:125)
    at org.jruby.runtime.Block.call(Block.java:101)
    at org.jruby.RubyProc.call(RubyProc.java:290)
    at org.jruby.RubyProc.call(RubyProc.java:228)
    at org.jruby.javasupport.JavaUtil$1.call(JavaUtil.java:237)
    at org.jruby.runtime.Helpers$MethodMissingMethod.call(Helpers.java:451)
    at org.jruby.gen.InterfaceImpl1135145813.run(org/jruby/gen/InterfaceImpl1135145813.gen:13)
    at java.lang.Thread.run(Thread.java:744)
Caused by: java.lang.ClassNotFoundException: org.jruby.util.ConvertDouble
    at java.net.URLClassLoader$1.run(URLClassLoader.java:366)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:425)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:358)
    ... 50 more

If I were to java_import 'org.jruby.util.ConvertDouble' and java_import 'org.jruby.embed.variable.Argv', this exception would disappear and be replaced with other java.lang.NoClassDefFoundError exceptions about missing JRuby classes.

I'm wondering if including jruby-complete in the jbundler Jarfile is not enough, and if I need to explicitly import the JRuby runtime. However, I'm just starting with JRuby and I'm not sure how to do that. I've used other JVM-based languages whose build tools manage this process automatically, but this is a more manual process and I might be missing something.

Owner

mkristian commented May 1, 2014

import_java will load these classes into the jruby-classloader which has
you application classloader as parent. the jruby-classloader does not have
those org.jruby.* since the parent classloader is the one which has all the
jruby classes.

so you telling that import_java helps, and the exception is

EvalFailedException

assuming an eval of some kind took place.

you did play around with jbundler executable itself. did that work ?
if you could provide some small proof of concept code - that would be very
helpful.

jruby-complete is indeed complete ;)

maybe warbler removes the META-INF/jruby.home part but your remarks are
more not about missing ruby files from stdlib.

On Thu, May 1, 2014 at 5:04 PM, Joshua Griffith notifications@github.comwrote:

Yes, all of the libraries are part of the Jarfile and I am running java
-jar my.jar and it does sound like a classloader issue with JRuby's
runtime.

When executing the application with JRuby (not packaged as a standalone
Jar), it runs without exception, thanks to jbundler downloading all of the
required Jar dependencies. When packaged as a Jar, exceptions seem to
concern JRuby classes that cannot be found—as if parts of the JRuby runtime
are not imported. The other libraries will load and run without issue until
they return something that appears to require JRuby reflection. Here's an
example that occurs during a shutdown hook:

error: org.jruby.embed.EvalFailedException: java.lang.NoClassDefFoundError: org/jruby/embed/variable/Argv
Exception in thread "Thread-6" java.lang.NoClassDefFoundError: org/jruby/util/ConvertDouble
at org.jruby.RubyNumeric$ByteListCaller19.yield(RubyNumeric.java:387)
at org.jruby.RubyNumeric.str2fnumCommon(RubyNumeric.java:364)
at org.jruby.RubyNumeric.str2fnum19(RubyNumeric.java:358)
at org.jruby.RubyString.to_f19(RubyString.java:4565)
at org.jruby.RubyString$INVOKER$i$0$0$to_f19.call(RubyString$INVOKER$i$0$0$to_f19.gen)
at org.jruby.runtime.callsite.CachingCallSite.cacheAndCall(CachingCallSite.java:306)
at org.jruby.runtime.callsite.CachingCallSite.call(CachingCallSite.java:136)
at org.jruby.ast.CallNoArgNode.interpret(CallNoArgNode.java:60)
at org.jruby.ast.CallOneArgFixnumNode.interpret(CallOneArgFixnumNode.java:59)
at org.jruby.ast.LocalAsgnNode.interpret(LocalAsgnNode.java:123)
at org.jruby.ast.NewlineNode.interpret(NewlineNode.java:105)
at org.jruby.ast.BlockNode.interpret(BlockNode.java:71)
at org.jruby.evaluator.ASTInterpreter.INTERPRET_METHOD(ASTInterpreter.java:74)
at org.jruby.internal.runtime.methods.InterpretedMethod.call(InterpretedMethod.java:139)
at org.jruby.internal.runtime.methods.DefaultMethod.call(DefaultMethod.java:182)
at org.jruby.runtime.callsite.CachingCallSite.cacheAndCall(CachingCallSite.java:306)
at org.jruby.runtime.callsite.CachingCallSite.call(CachingCallSite.java:136)
at org.jruby.ast.VCallNode.interpret(VCallNode.java:88)
at org.jruby.ast.NewlineNode.interpret(NewlineNode.java:105)
at org.jruby.ast.BlockNode.interpret(BlockNode.java:71)
at org.jruby.ast.IfNode.interpret(IfNode.java:116)
at org.jruby.ast.NewlineNode.interpret(NewlineNode.java:105)
at org.jruby.ast.BlockNode.interpret(BlockNode.java:71)
at org.jruby.evaluator.ASTInterpreter.INTERPRET_METHOD(ASTInterpreter.java:74)
at org.jruby.internal.runtime.methods.InterpretedMethod.call(InterpretedMethod.java:139)
at org.jruby.internal.runtime.methods.DefaultMethod.call(DefaultMethod.java:182)
at org.jruby.runtime.callsite.CachingCallSite.cacheAndCall(CachingCallSite.java:306)
at org.jruby.runtime.callsite.CachingCallSite.call(CachingCallSite.java:136)
at org.jruby.ast.VCallNode.interpret(VCallNode.java:88)
at org.jruby.ast.IfNode.interpret(IfNode.java:116)
at org.jruby.ast.NewlineNode.interpret(NewlineNode.java:105)
at org.jruby.ast.BlockNode.interpret(BlockNode.java:71)
at org.jruby.evaluator.ASTInterpreter.INTERPRET_METHOD(ASTInterpreter.java:74)
at org.jruby.internal.runtime.methods.InterpretedMethod.call(InterpretedMethod.java:139)
at org.jruby.internal.runtime.methods.DefaultMethod.call(DefaultMethod.java:182)
at org.jruby.runtime.callsite.CachingCallSite.cacheAndCall(CachingCallSite.java:306)
at org.jruby.runtime.callsite.CachingCallSite.call(CachingCallSite.java:136)
at org.jruby.ast.CallNoArgNode.interpret(CallNoArgNode.java:60)
at org.jruby.ast.NewlineNode.interpret(NewlineNode.java:105)
at org.jruby.evaluator.ASTInterpreter.INTERPRET_BLOCK(ASTInterpreter.java:112)
at org.jruby.runtime.Interpreted19Block.evalBlockBody(Interpreted19Block.java:206)
at org.jruby.runtime.Interpreted19Block.yield(Interpreted19Block.java:194)
at org.jruby.runtime.Interpreted19Block.call(Interpreted19Block.java:125)
at org.jruby.runtime.Block.call(Block.java:101)
at org.jruby.RubyProc.call(RubyProc.java:290)
at org.jruby.RubyProc.call(RubyProc.java:228)
at org.jruby.javasupport.JavaUtil$1.call(JavaUtil.java:237)
at org.jruby.runtime.Helpers$MethodMissingMethod.call(Helpers.java:451)
at org.jruby.gen.InterfaceImpl1135145813.run(org/jruby/gen/InterfaceImpl1135145813.gen:13)
at java.lang.Thread.run(Thread.java:744)
Caused by: java.lang.ClassNotFoundException: org.jruby.util.ConvertDouble
at java.net.URLClassLoader$1.run(URLClassLoader.java:366)
at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
at java.lang.ClassLoader.loadClass(ClassLoader.java:425)
at java.lang.ClassLoader.loadClass(ClassLoader.java:358)
... 50 more

If I were to java_import 'org.jruby.util.ConvertDouble' and java_import
'org.jruby.embed.variable.Argv', this exception would disappear and be
replaced with other java.lang.NoClassDefFoundError exceptions about
missing JRuby classes.

I'm wondering if including jruby-complete in the jbundler Jarfile is not
enough, and if I need to explicitly import the JRuby runtime.


Reply to this email directly or view it on GitHubhttps://github.com/jruby/warbler/issues/261#issuecomment-41924243
.

Contributor

hadronzoo commented May 5, 2014

I solved the issue. I was calling JRuby code within a Java shutdown hook, rather than using at_exit. It appears that JRuby is already unloaded by the time Java shutdown hooks are fired.

hadronzoo closed this May 5, 2014

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment