Create  Edit  Diff  FrontPage  Index  Search  Changes  Login

RubyJavaBridge

rjb is my new bridge.

RubyJavaブリッヂ

https://rubygems.org/gems/rjb

ASR-1.8.7 also contains rjb-1.2.6 binary

Release notes

How to install rjb

Execute gem install command, and select number. If select 1(not mswin32), add PATH environment `javah' and `javac' containts directory before execute gem command.

#example
#bash
export PATH=$PATH:$JAVA_HOME/bin
#tcsh
setenv PATH=$PATH:$JAVA_HOME/bin

If you install to Cygwin, set JAVA_HOME environment make consistent with Cygwin before execute gem command.

#example
export JAVA_HOME=$(cygpath -ua $JAVA_HOME)

Execute gem command.

# gem install rjb

Beware! Install incomple if no set environment variables before install. back then execute 'gem uninstall rjb' and 'gem install rjb'.

How to use rjb

jvm is required

For example, if you use Linux with Sun j2se, you need to set LD_LIBRARY_PATH points j2se shared objects explicitly.

sh, bash:

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$JAVA_HOME/jre/lib/i386:$JAVA_HOME/jre/lib/i386/client

csh, tcsh:

setenv LD_LIBRARY_PATH $LD_LIBRARY_PATH:$JAVA_HOME/jre/lib/i386:$JAVA_HOME/jre/lib/i386/client

in AMD64 Linux

Java for AMD64 Linux has one issue to use Rjb. The shared object that came with JRE causes 'unknown exception'.

The workaround is to put LD_PRELOAD environment variable before invoking the script.

For example to run Rails sciprt/server as:

% LD_PRELOAD=/opt/jdk1.5.0_09/jre/lib/amd64/libzip.so script/server

The pathname '/opt/jdk1.5.0_09/jre/lib/amd64' is varied.

(26 Dec. 2006 added by arton: id:odz has helped to explore this issue, thanks)

in RoR

Both LD_LIBRARY_PATH and JAVA_HOME setting required in environment.rb file of RoR.

Setting them in the apache conf didn't seem to work.

This tip was contributed by Ruban Phukan, Thanks Ruban.

(03 Nov. 2006 - Wes Gamble added:

Using Apache + FastCGI, if you set JAVA_HOME and LD_LIBRARY_PATH in the FastCGI module configuration file using the -initial-env option, like so:

-initial-env RAILS_ENV=production \
-initial-env JAVA_HOME=/usr/java/jdk1.5.0_09 \
-initial-env LD_LIBRARY_PATH=${JAVA_HOME}/jre/lib/i386,

then RJB will work without specifying these environment variables in environment.rb.)

(Thanks Wes, I updated RubyForge? top page with your text. http://rjb.rubyforge.org/ - arton)

in Windows

you never need to set LD_LIBRARY_PATH, because they can be loaded and bound into the process dynamically. (it may cause any vulnelability ?)

in OS X

  • on OS X, rjb does not look up JAVA_HOME environment variable, but /System/Library/Frameworks/JavaVM.framework/Libraries/libjvm_compat.dylib directly. So you need to set appropriate Java version using /System/Library/Frameworks/JavaVM.framework/Libraries symbolic link.
    • thanks Adam.

rjb is required

require 'rjb'

load jvm

Rjb::load(classpath = '.', jvmargs=[])

classpath is a client supplied runtime classpath. Rjb appends this string before ENV['CLASSPATH'] using PATH_SEP character. (rjb-0.1.8)

jvmargs is a string array. Its elements are the jvm arguments. (rjb-0.2.0)

ex)

Rjb::load(nil, ['-verbose:gc', '-Dfoo.bar=FooBar'])

import java class into ruby

str = Rjb::import('java.lang.String')  # import String class into the varibale 'str'

After this call, the variabe 'str' contains java.lang.String class.

instanciate an object

instance = str.new

This means that

String instance = new String();

For java.lang.String, you'd like to call the constructor with some arguments like

String instance = new String("hiki is a wiki engine");
// in Java, this call was nonesence because String is imutable...

With rjb, you need to specify type informations for theses overloaded methods.

instance = str.new_with_sig('Ljava.lang.String;', 'hiki is a wiki engine')
klass#new_with_sig(sig, arg[, more args])
invoke constructor with type informations
sig
type signature. You can find the type names at J2SE's Class#getName API documentation as arrays's encoded element type names.
type nameencoded name
booleanZ
byteB
charC
class or interfaceLclassname;
doubleD
floatF
intI
longJ
shortS

auto type matching rules

Since rjb-0.1.4, it supposes the method by the arguments.

  1. match the number of the arguments.
  2. if the argument instanceof Object and the parameter type instanceof Object, it matches.
  3. FIXNUM matches any one of BCDFIJS.
  4. STRING matches java.lang.String.
  5. TRUE/FALSE match Z.
  6. ARRAY matches any types of the array.
  7. Rjb imported object matches java.lang.String, the class or the subclass. If String, Object#toString will be called to create String object.
  8. Any matches the Object type.

more example

irb(main):001:0> require 'rjb'
=> true
irb(main):002:0> Str = Rjb::import('java.lang.String')
=> #<Rjb::Java_lang_String:0x2c64ba0>
irb(main):003:0> s = Str.new_with_sig('[BLjava.lang.String;', [48, 49, 50], 'Windows-31j')
=> #<#<Class:0x2c6a2b8>:0x2c5c3f8>
irb(main):004:0> p s.toString
"012"
=> nil
irb(main):005:0>

call instance method (none overloaded)

in Java

String instance2 = instance.replaceAll("hiki", "rwiki");

in rjb

s = instance.replaceAll('hiki', 'rwiki')

in rjb, returned String coerces to ruby's String, not java.lang.String instance.

rubyize method name (since rjb-1.0.6)

Rjb treats Java's method name as ruby's to change capitalize letter to an underscode and a small letter.

ex)

s = instance.replace_all('hiki', 'rwiki')

as

s = instance.replaceAll('hiki', 'rwiki')

call overloaded method (with type informations)

you need to call with obj#_invoke as

instance2 = instance._invoke('replaceAll', 'Ljava.lang.String;Ljava.lang.String;', 'hiki, 'rwiki')
obj#_invoke(name, sig, arg[, more args])
invoke a method with name 'name' with type informations
name
the name of the method to be called
sig
type signature. You can find the type names at J2SE's Class#getName API documentation as arrays's encoded element type names.

return value conversion (since rjb-1.0.8)

Natively Rjb treats Java's returned values as they are.

If the value is primitive, then convert it to Ruby's native. For example Java's int to Ruby's Fixnum, Java's boolean as Ruby's TrueClass? or FalseClass etc.

In the same matter, Rjb don't convert if the return value was an object. So, if Java's method returned java.lang.Integer object, then Rjb passes the value as Java_Lang_Integer object.

You can change this behavior with setting Rjb::primitive_conversion psuedo variable to true.

ex)

jInteger = Rjb::import 'java.lang.Integer'
obj = jInteger.valueOf '19' # obj is an instance of Java_Lang_Integer class
puts obj.intValue # => 19
Rjb::primitive_conversion = true
obj = jInteger.valueOf '20' # obj is an instance of Ruby's Fixnum
puts obj          # => 20

The default value of Rjb::primitive_conversion is false.

accessing fields

  • static field is ok (rjb-0.1.2)
>ruby -rrjb -e "Rjb::import('java.lang.System').out.println('Just Another Ruby Hacker')"
Just Another Ruby Hacker
>
  • instance field is ok too (rjb-0.1.2)
require 'rjb'
pnt = Rjb::import('java.awt.Point')
p = pnt.new(0, 0)
p.y = 80
puts "x=#{p.x}, y=#{p.y}"
=>
x=0, y=80

bind Ruby object to Java interface

You can bind Ruby object to Java interface as long as the object has responsable to respond the method call from Java world.

class Comparable
  def initialize(val)
    @value = val
  end
  def compareTo(oponent)
    return @value - oponent.to_i
  end
end
cp = Comparable.new(3)
cp = Rjb::bind(cp, 'java.lang.Comparable')
bind(obj, name)
bind ruby object and Java interface
obj
ruby object
name
Java's interface name
return
new object that's bound to the specified interface

throws java exception in ruby-bounded-object (rjb-0.1.9)

You can throw java exception from the bounded object.

class Iterator
  def hasNext()
    true
  end
  def next()
    Rjb::throw('java.util.NoSuchElementException', 'test exception')
  end
end

This code throws NoSuchElementException? with a message 'test exception' while the caller calls Iterator#next.

throw(classname, message)
throw an exception object.
classname
string that represents throwable class.
message
string that describes the cause.

inspect object's class

Rjb adds a method named _classname for each instance. This method returns the name of its class.

obj#_classname
return the java class name

ex)

require 'rjb'
out = Rjb::import('java.lang.System').out
p out._classname
out.println('jarh')

result)

"java.io.PrintStream"
jarh

The encoding that is guessed by $KCODE

Ruby supports a character code of EUC-JP,Shift_JIS,UTF-8,NONE and changes it in $KCODE. $KCODE in the case of NONE, guess encoding. Rules changed in rjb-0.1.2(trunk(rev.31)). Rules as is follow.

$KCODEguess ruleoriginal encoding
E euc-jp
S cp932
U not conversion
N Windows && GetACP() == 932cp932
Windows && GetACP() != 932not conversion
Locale && sjis shift_jis
Locale && euc-jp euc-jp
Locale && utf-8 not conversion
Locale && other not conversion
other not conversion

If match case of "not conversion", Ruby string must be converted to UTF-8 before binding. In this case, Rjb calls "NewStringUTF" of JNI API so it must point the UTF-8 chars.

String encoding conversion rule for ruby 1.9.x

m17n was included in Ruby1.9.0. Handling of the string was changed.

Ruby to Java

When String#encoding return Shift_JIS/EUC-JP/ISO-2022-jp, convert to utf-8. Otherwise string is not conversion.

Java to Ruby

Don't convert it automatic. Set Encoding::UTF_8 to String#encoding.

How To Build Rjb

Internal mechanism

Online sites to consider

Last modified:2021/02/10 08:47:24
Keyword(s):
References: