FAQs
- Execution Environments
- General
- Running Rails
- Calling Into Java
- Java and JRuby Interoperation
- Troubleshooting
- Networking
Somewhat. See JRuby on JME.
Here is a page dedicated to answering this question: JRuby on Web Start
Include a "hash bang" line on the top of your jruby script like this:
#!/usr/bin/env jruby
That will use the system wide installed jruby interpreter to run your script.
If you would like to use a local copy of JRuby to run your script, give the relative or absolute path to the jruby program:
#!/usr/bin/env jruby-1.6.8/bin/jruby
To run the script directly, you need to set the "x" flag on it:
chmod +x your_script.rb
You can now start your script with
./your_script.rb
You can also try the jruby-launcher gem
, which installs a native jruby
program.
jruby -S gem install jruby-launcher
Now you can place the full path to JRuby in the shebang line, along with parameters if you wish:
#!/usr/local/jruby/bin/jruby -w
Passing the standard -Xmx<size>
flag to the JVM, either via the JAVA_OPTS
environment variable or by adding -J-Xmx<size>
to JRUBY_OPTS
will set the maximum size for the main JRuby process and any JRuby subprocesses that it starts. You may also set this in the environment before or during the launch of that subprocess to control memory size on a per-process basis.
See Troubleshooting Memory Use.
On Windows, the native jruby.exe
launcher usually loads the JVM's DLL directly and spins up the JVM in
the same process, rather than launching an external process using the java.exe
command. However, -splash
and a few other options are only supported by the java.exe
command and are unrecognized by the DLL.
Because we have no way of knowing what options are or are not supported by the DLL, we provide a flag for the
jruby.exe
command to force using java.exe
and spinning an external process: -Xfork-java
. Passing this flag to the jruby
command line will allow those other java.exe
-only flags to work correctly.
JRuby's launchers will use java.exe
by default for the Java command. However this requires a command prompt to be present, and if launched as a shortcut it will open up such a prompt in the background.
You can change the Java command used with the JAVACMD
environment variable:
C:\somedir> set JAVACMD=javaw.exe
C:\somedir> jruby myscript ; launches in background without blocking the terminal
The Ruby Language Home Page has links to a wide range of resources for learning about Ruby, downloading releases of the C implementation of Ruby, documentation on Ruby, and community outlets for talking about Ruby.
The Pragmatic Programmers are the publishers of the de facto standard Ruby text, "Programming Ruby". It is considered a must-have manual to the Ruby language and libraries.
Almost everything you learn about the Ruby language is directly applicable to working with JRuby. JRuby aims to be a drop-in replacement for the C implementation of Ruby.
See Differences Between MRI and JRuby.
Yes. JRuby officially started supporting 1.9.2 features as of the 1.6.x line of releases, though it
is not default in those versions. You must specify the --1.9
flag at the command line or in a JRUBY_OPTS
environment variable, or add "compat.version=1.9" to .jrubyrc (on 1.6.5 or higher).
Ruby 1.9 mode is default in JRuby 1.7.0 and later, 1.8.7 compatibility can still be used with the --1.8
flag.
Frequently users want to run JRuby from NetBeans, from Eclipse, launched from an existing Java application, or in other ways that don't use the command-line scripts. In addition to having jruby.jar
and its dependency jars available in CLASSPATH, you must also have the following system property set:
-Djruby.home=<path-to-root-of-JRuby-installation>
You might also want to ensure the maximum memory is set higher than the JVM default. JRuby's own command-line scripts use a maximum of 256MB.
You have two options:
- Always invoke JRuby with e.g.,
jruby -S gem
. - Put a handy bash snippet like this in your .bashrc to create
j
aliases to all the available commands (rails
becomesjrails
,rake
becomesjrake
, etc.)
for f in $JRUBY_HOME/bin/*; do
f=$(basename $f)
case $f in jruby*|jirb*|*.bat|*.rb|_*) continue ;; esac
eval "alias j$f='jruby -S $f'"
done
JRuby can only see the gems installed with the gem command shipped with JRuby. The gems installed this way will be stored under $JRUBY_HOME/lib/ruby
. If you try to run Rails and get the error, "Cannot find gem for Rails ~>1.2.2.0:" (or whatever version you are using), the problem is probably that you haven't installed the Rails-gem and its dependencies with the JRuby gem-command.
When I implement a Java interface and provide my own initialize method, I can't construct it anymore.
In JRuby 0.9.0, any class implementing a Java interface must explicitly call super
in their initializers to set up the interface proxy. Add a super
call to your implementation's initialize
method and it should work.
If you don't want to launch JRuby as a separate process, we recommend you use the Bean Scripting Framework (BSF) or Java 6's Scripting Support (JSR223). We do not recommend calling directly into the JRuby runtime, since that code is subject to change.
You need to do something along the lines of:
try {
rubyCode.doSomething();
} catch (RaiseException e) {
e.getException().printBacktrace(System.err);
}
Note that Java 6's scripting via the BSF libraries might not preserve stack traces, and also launches more slowly. It's often preferable (as of February 2007) to use JRuby's own integration.
Why do I get a java.lang.NoSuchMethodError: org.objectweb.asm.ClassWriter.visit()
error when running JRuby 1.X with a custom classpath?
The problem stems from an ASM jar conflict. It was found by setting a custom classpath, which includes a version of Spring that has a conflicting ASM jar, and then invoking JRuby. The easiest workaround is to build jruby-complete
as a single jar and edit the JRuby config file (not sure about Windows, but it should be similar) to source only the jruby-complete
jar. You will need to add ALL other jars, which I believe includes your jdbc driver as well.
svn co http://svn.codehaus.org/jruby/tags/jruby-1_0/
cd jruby-1_0
ant jar-complete
vi bin/jruby (see diff for edit)
#diff bin/jruby bin/jruby.orig
#89c89
#< for j in "$JRUBY_HOME"/lib/jruby-complete.jar; do
#---
#> for j in "$JRUBY_HOME"/lib/*.jar; do
How come Java can't find resources in class folders that I've appended to the $CLASSPATH global variable at runtime?
JRubyClassLoader extends java.net.URLClassLoader
, which treats any URL that doesn't end with a slash as a jar. See URLClassLoader.
The file encoding for the .rb
file containing the special characters must be set to UTF-8.
Use the JRUBY_VERSION
constant.
% jruby -rjava -e "puts java.lang.System.get_property('java.version')"
This happens if you require ActiveRecord-JDBC in your environment, but you haven't installed the gem. Make sure you have the ActiveRecord-JDBC gem installed.
It is possible to set the GEM_HOME directory to a common one, but numerous users reporting weird behavior makes us recommend not setting a common GEM_HOME. DO NOT DO IT :)
The main problem arises that various gems have dependences on native gems. If you install with MRI it will install the c-extension version and not work with JRuby. If you install with JRuby it will not work with MRI. Hitting one of these gems, like Nokogiri, is much too common for this to be worth it. You just need to set GEM_HOME to point to your CRuby's gem directory. For example, in tcsh:
I get the error "undefined method 'cattr_accessor' for ActiveRecord::Base:Class (NoMethodError)" after configuring activerecord-jdbc-adapter. What is wrong?
You're not loading AR-JDBC properly. Try requiring activerecord-jdbc-adapter in config/environment.rb
:
require 'activerecord-jdbc-adapter' # or require 'arjdbc'
If you're using Bundler this is not needed just make sure there's no :require => nil/false
with the gem declaration :
gem 'activerecord-jdbc-adapter' # will auto require 'activerecord-jdbc-adapter'
You might not have set the production DB settings in database.yml
properly. Goldspike by default builds a war that runs the app in production mode.
You can confirm the problem by finding the production.log
file. If you're using JBoss, then it lives in $JBOSS_HOME/server/my_app/tmp/my_rails_war
''1234''.war
, where ''1234'' is a random number generated by JBoss.
In production.log
, you'll see an error this:
RuntimeError (The driver encountered an error: can't convert nil into String)
To fix this, just set the production DB settings in database.yml
properly.
You can add the config directory to the JRuby classpath in config/environment.rb
:
require 'java'
$CLASSPATH << "file:///#{File.expand_path(File.join(RAILS_ROOT, 'config'))}/"
Now, because ResourceBundle.getBundle
doesn't seem to use the JRuby class loader, we need to pass it explicitly. In the file where you want to use the resource bundle do :
include Java
require 'jruby'
...
bundle = java.util.ResourceBundle::getBundle
("i18n", java.util.Locale::FRENCH, JRuby.runtime.jruby_class_loader)
Now you just need to put your i18n[_*].properties
files in config/
, et voilà!
When JRuby runs at the command line, it loads into the bootstrap class loader. This class loader lives above CLASSPATH, so libraries you add to CLASSPATH are not normally visible. Because Class.forName
uses the class loader of the nearest non-system class that called it, it ends up seeing JRuby as the caller and looking for classes only in CLASSPATH.
The workaround for this is simple: Uuse JRuby's import or include_class methods to load the class, or just reference it directly as in Java::my.package.MyClass
or org.postgresql.Driver
.
Sometimes, developers name their inner classes beginning with a lowercase letter. This prevents JRuby from accessing it the "normal way" (it thinks it's a method). For example:
In Java (from the com.sun.enterprise.ee.cms.core
package of the Shoal project)
GMSConstants.shutdownType.INSTANCE_SHUTDOWN
Whereas in JRuby, you can get at that using the following:
>> ShutdownType = JavaUtilities.get_proxy_class('com.sun.enterprise.ee.cms.core.GMSConstants$shutdownType')
You can convert existing ruby arrays to primitive Java arrays very simply:
[1,2,3].to_java # makes an object array
[1,2,3].to_java :byte # makes a byte array
[1,2,3].to_java :String # makes a String array
To create empty arrays:
Java::byte[12].new # makes a new byte[]
java.lang.String[12].new # makes a new String[]
There are two separate ways:
- Include an interface into the class.
class MyListener
include java.awt.event.ActionListener
def actionPerformed(event)
button.text = "I have been pressed"
end
end
- Use implicit closure conversion.
button.add_action_listener { |event| button.text = "I have been pressed" }
You can do an Ahead-Of-Time (AOT) compile by using these instructions.
Add .bat
extension to JRuby scripts.
If you try to run JRuby on cygwin for Windows and use the commands without the .bat
extension, it will default to the bourne shell versions, which might not work properly.
Example using gems:*
$JRUBY_HOME/bin/gem.bat install rails -y --no-ri --no-rdoc
Why does my db:migrate fail with "undefined method 'create_database' for class '#Class:01x1e30857'"?
In this case, try to run the migrations with:
jruby -S rake db:migrate SKIP_AR_JDBC_RAKE_REDEFINES=1
You can also just put the following line somewhere in your Rakefile, or in a custom Rakefile in lib/tasks/*.rake
:
ENV['SKIP_AR_JDBC_RAKE_REDEFINES'] = '1'
There are two scenarios in which JNI problems occur:
- When the jar is in JRuby 1.1.2's lib.
- When the jar is loaded using ruby's "require" statement in JRuby < 1.1.
These two scenarios are described below.
JRuby 1.1.2 +
JRuby 1.1.2 changed how it set up the classpath. Earlier versions merged the CLASSPATH environment variable with all .jar files in JRUBY_HOME/lib
and passed them to the JVM via the -classpath
option. JRuby 1.1.2 instead passes all .jar
files in lib
to the JVM via the -Xbootclasspath/a:
option, while CLASSPATH is passed using -classpath
. Jar files that use JNI (e.g. sqljdbc.jar
) don't work correctly when they're in the boot classpath, so they should not be placed in JRuby's lib
directory. Instead, they should be loaded with require
or by setting the CLASSPATH environment variable.
You tried the performance tuning option --server but received an error like "Error: no server' JVM at
c:\Program Files\Java\jre6\bin\server\jvm.dll'."
On windows the Java Runtime Environment (JRE) inclues the client VM by default but does not include the server VM. You should download an install the Java Development Kit (JDK).
If you want to use the server VM with the JRE, you can copy JDK's jre\bin\server folder to a bin\server directory in the Java SE Runtime Environment.
This error is reported when the JDK or JRE you're running on does not allow stronger encryption. There are a few different ways to work around it.
My server seems to have many threads stuck waiting on a Mutex, and I'm not getting good concurrency and request throughput. Why?
If you force a dump of threads on the server JVM, you may see a stack trace like this:
"qtp368471295-36" prio=10 tid=0x00007fbf987c6800 nid=0xa277 waiting on condition [0x00007fbf2c99c000]
java.lang.Thread.State: WAITING (parking)
at sun.misc.Unsafe.park(Native Method)
- parking to wait for <0x000000070a1e7968> (a java.util.concurrent.locks.ReentrantLock$NonfairSync)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:158)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:811)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireInterruptibly(AbstractQueuedSynchronizer.java:867)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireInterruptibly(AbstractQueuedSynchronizer.java:1201)
at java.util.concurrent.locks.ReentrantLock.lockInterruptibly(ReentrantLock.java:312)
at org.jruby.RubyThread.lockInterruptibly(RubyThread.java:1468)
at org.jruby.ext.thread.Mutex.lock(Mutex.java:91)
at org.jruby.ext.thread.Mutex$INVOKER$i$0$0$lock.call(Mutex$INVOKER$i$0$0$lock.gen)
at org.jruby.runtime.callsite.CachingCallSite.call(CachingCallSite.java:134)
at rubyjit.Rack::Lock$$call_9D2E3A2DC6D4739AEFA0FEFD72B6C9712EF582B8.chained_0_ensure_1$RUBY$__ensure__(/data/app/taxman/installs/taxman_110bbe712d8bf6ee3955b8e87573c2cc278fe20a/vendor/bundle/jruby/1.9/gems/rack-1.4.5/lib/rack/lock.rb:14)
at rubyjit.Rack::Lock$$call_9D2E3A2DC6D4739AEFA0FEFD72B6C9712EF582B8.__file__(/data/app/taxman/installs/taxman_110bbe712d8bf6ee3955b8e87573c2cc278fe20a/vendor/bundle/jruby/1.9/gems/rack-1.4.5/lib/rack/lock.rb)
at rubyjit.Rack::Lock$$call_9D2E3A2DC6D4739AEFA0FEFD72B6C9712EF582B8.__file__(/data/app/taxman/installs/taxman_110bbe712d8bf6ee3955b8e87573c2cc278fe20a/vendor/bundle/jruby/1.9/gems/rack-1.4.5/lib/rack/lock.rb)
at org.jruby.internal.runtime.methods.JittedMethod.call(JittedMethod.java:181)
at org.jruby.runtime.callsite.CachingCallSite.call(CachingCallSite.java:168)
at rubyjit.ActionDispatch::Static$$call_98B9D217DEE0C8798054918A3A9A20D7242072EA.__file__(/data/app/taxman/installs/taxman_110bbe712d8bf6ee3955b8e87573c2cc278fe20a/vendor/bundle/jruby/1.9/gems/actionpack-3.2.16/lib/action_dispatch/middleware/static.rb:63)
at rubyjit.ActionDispatch::Static$$call_98B9D217DEE0C8798054918A3A9A20D7242072EA.__file__(/data/app/taxman/installs/taxman_110bbe712d8bf6ee3955b8e87573c2cc278fe20a/vendor/bundle/jruby/1.9/gems/actionpack-3.2.16/lib/action_dispatch/middleware/static.rb)
...
The trace above indicates there's a single JRuby runtime handling many concurrent requests, but Rails's "threadsafe" mode is not enabled. As a result, Rails inserts a lock acquisition into the request pipeline, and requests execute in serial. Generally, when deploying on JRuby, you will want to either be running threadsafe mode (single JRuby runtime, many concurrent requests) or non-threadsafe mode but with many JRuby instances.
You should modify the Rails config for your application to enable threadsafe mode: http://apidock.com/rails/Rails/Configuration/threadsafe!
Java on OS X adds additional folders (nonstandard) to the classpath. /Library/Java/Extensions
and ~/Library/Java/Extensions
can contain additional .jar files, which are automatically made available to Java. However, if you have a .jar in Extensions
that also happens to be used by JRuby (but are different versions, or were compiled for an older version of Java) having both in the classpath can cause conflicts. You can examine the classpath from irb, by checking the $CLASSPATH
global variable, which will list all .jar files used by JRuby which are in the classpath.
One common error caused by having two conflicting versions of the same class on the classpath include:
java.lang.VerifyError: class org.bouncycastle.asn1.ASN1Primitive overrides final method equals
To resolve the issue, either remove the conflicting .jar from the Extensions
directory, or swap it for a version that is compatible with the version used by JRuby.
This is likely due to entropy starvation. See the Improving startup time page's section on addressing entropy starvation.
Some misconfigured environments may see the following errors when the Psych YAML library tries to load:
% jruby -S bundle install
/home/enebo/work/jruby/lib/ruby/stdlib/psych.rb:7: warning: already initialized constant SNAKEYAML_VERSION
/home/enebo/work/jruby/lib/ruby/stdlib/psych.rb:7: warning: already initialized constant ANY
/home/enebo/work/jruby/lib/ruby/stdlib/psych.rb:7: warning: already initialized constant UTF8
/home/enebo/work/jruby/lib/ruby/stdlib/psych.rb:7: warning: already initialized constant UTF16LE
/home/enebo/work/jruby/lib/ruby/stdlib/psych.rb:7: warning: already initialized constant UTF16BE
org/jruby/RubyKernel.java:984: warning: It seems your ruby installation is missing psych (for YAML output).
To eliminate this warning, please install libyaml and reinstall your ruby.
LoadError: load error: psych -- java.lang.NoClassDefFoundError: Could not initialize class org.jruby.ext.psych.PsychEmitter
LoadError: load error: psych -- java.lang.NoClassDefFoundError: Could not initialize class org.jruby.ext.psych.PsychEmitter
...
or...
% jruby -d -S bundle install
java.lang.NoSuchMethodError: org.yaml.snakeyaml.error.Mark.<init>(Ljava/lang/String;III[II)V
...
JRuby's implementation of the Psych YAML extension uses a Java library called SnakeYAML. An incompatible API change in the 1.1x versions was reverted in 1.21. However the broken versions are still out there and sometimes creep into user environments via default CLASSPATH or transitive dependencies in larger JRuby/Java apps. The broken API will trigger the errors above.
To fix this, you must make sure we are able to load the version of SnakeYAML that ships with JRuby (at least 1.21 or higher). Check your environment for CLASSPATH variables, or check your Java dependencies for transitive dependency on an older version of SnakeYAML.
Related issues:
- https://github.com/bundler/bundler/issues/6878
- https://github.com/jruby/jruby/issues/6023
- https://github.com/actions/virtual-environments/issues/242
- https://github.com/ruby/psych/issues/428
MRI/CRuby and JRuby appear to have some differences in how they resolve "localhost". On JRuby, sometimes we will resolve it as an IPv4 address and sometimes as an IPv6 address, and CRuby seems to sometimes choose the opposite. As a result, using "localhost" on both ends may result in failed connections, usually with a "connection refused" or a family/protocol error. Specifying the exact IPv4 or IPv6 address on each end (e.g. http://[::1]:4567
or http://0.0.0.0:4567
vs http://localhost:4567
) is often the easiest workaround.
Additionally, some JDKs (like OpenJDK/Sun/Oracle/Hotspot) try to use IPv6 addresses for e.g. "localhost" when possible. If using only similar JDKs to connect, this isn't a problem. However, some tools usually prefer one protocol or the other and may have trouble connecting.
You can adjust how the JDK (at least OpenJDK/Sun/Oracle/Hotspot) decides to use IPv6 versus IPv4 addresses via these networking properties. You can add them to the Java startup options like this:
export JAVA_OPTS="-Djava.net.preferIPv4Stack=true"
jruby ...
Or pass directly to JRuby using -J-D like this:
jruby -J-Djava.net.preferIPv4Stack=true ...
The equivalent property for IPv6 java.net.preferIPv6Stack
, but some JVMs may do this by default.