让一个ruby和java同时不熟悉的人搞这个,真是很晕啊!!!
Rjb - Ruby Java Bridge
rjb是一个桥梁程序,连接ruby和java的。
ASR-1.8.x package也包含了rjb的最新版本。
已知的限制:Rjb只支持JVM的主线程。至少你不能从JVM工作线程中调用ruby的垃圾处理器。它会引起一些错误。
Rjb的使用场景
- Rake + Rjb 是 比Maven 和 Ant 更强大和有用的构建工具
- 你可以使用Rjb模拟来测试java业务逻辑类
- 在Ruby on Rails 程序中移植结构对象有用
- 但是小心构建连接程序,Ruby(和Rjb)不考虑JVM的线程处理
如何使用rjb
jvm是必须的
例如,如果你使用带有Sun j2se的linux, 你需要设置LD_LIBRARY_PATH来明确的指定j2se的共享对象。
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
在Ruby on Rails
需要设置LD_LIBRARY_PATH和JAVA_HOME.
ENV['JAVA_HOME'] = "/usr/java/jdk1.5.0_09"
ENV['LD_LIBRARY_PATH'] = "#{ENV['LD_LIBRARY_PATH']}:#{ENV['JAVA_HOME]}/jre/lib/i386:#{ENV['JAVA_HOME']}/jre/lib/i386/client"
(但是不确定设置LD_LIBARY_PATH是不是有用)
在apache中设置是没用的, 这个提示是由Ruban Phukan提供,谢谢Ruban.
在Ruby on Rails 带有 Apache + FastCGI
使用Apache + FastCGI, 如果你要在FastCGI的配置文件中设置JAVA_HOME和LD_LIBRAY_PATH可以使用-initial-env选项。如:
-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
这样Rjb在environment.rb不指定环境变量的情况下页可以工作,这个提示由Wes Gamble提供,感谢 Wes.
在windows
不需要设置LD_LIBRARY_PATH, 因为他们会被动态的载入到进程中。
在OS X
这次, rjb的test.rb一直测试失败,我也不知道哪里出了问题
请忽略这个问题(我会持续在这方面下工夫)
- 在OS X中,rjb不找JAVA_HOME的环境变量,它直接找/System/Library/Frameworks/JavaVM.framework/Libraries/libjvm_compat.dylib。 所以你需要使用/System/Library/Frameworks/JavaVM.framework/Libraries symbolic link设置正确的java版本。
rjb是必须的
require 'rjb'
载入jvm
Rjb::load(classpath = '.', jvmargs=[])
ClassPath是客户端提供的运行时类目录。Rjb使用PATH_SEP字符串连接到ENV[‘CLASSPATH’]之前。
jvmargs是字符串数组,是jvm的参数
ex.
Rjb::load(nil, ['-verbose:gc', '-Dfoo.bar=FooBar'])
如果你不需要指定类目录和JVM的参数,这部分可以跳过。
导入java Class到ruby
str = Rjb::import('java.lang.String') # import String class into the varibale 'str'
调用了这行代码, str就是java.langString类了。
实例化对象
instance = str.new
意思等同于
String instance = new String();
对于java.lang.String. 你可以调用带参数的构造函数像这样:
String instance = new String("hiki is a wiki engine");
// in Java, this call was nonesence because String is imutable...
使用RJB,你需要为不同的重载方法指定类型信息。
instance = str.new_with_sig('Ljava.lang.String;', 'hiki is a wiki engine')
klass#new_with_sig(sig, arg[, more args]) : 调用带类型信息的构造函数
sig意思是signature, 你可以在J2SE的Class#getName API文档中找到这些类别的名字。作为数组的编码过后的类型名称。
type Name | encoded name |
---|---|
boolean | Z |
byte | B |
chart | C |
class or interface | Lclassname; |
double | D |
float | F |
int | I |
long | J |
short | S |
自动类型匹配规则
- 参数数目
- 如果实参是Object的实例, 形参也是Object的实例 。则匹配成功
- FIXNUM 匹配所有的BCDFIJS (bcdfijs)
- STRING 匹配java.lang.String
- TRUE/FALSE 匹配Z
- ARRAY 匹配 任意类型的数组
- Rjb导入的对象匹配java.lang.String, 类,子类。Object#toString用来创建String对象。
- 任意的都匹配到Object的类型。
更多的例子
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>
调用实例的方法
在Java
String instance2 = instance.replaceAll("hiki", "rwiki");
在Ruby
s = instance.replaceAll('hiki', 'rwiki')
在rjb, 返回的字符串会强制转换成Ruby的字符串,而不是java.lang.String的实例。
调用重载的方法(带类型信息)
Rjb检查参数的类型,来确定调用哪个方法。但是它不完整(假设有这种情况,如果有三个方法 void foo(int), void foo(short), void foo(long), 当参数时30),这种情况你需要使用ojb#_invoke来调用。例如:
instance2 = instance._invoke('replaceAll', 'Ljava.lang.String;Ljava.lang.String;', 'hiki, 'rwiki')
obj#_invoke(name, sig, arg[, more args]) : 调用一个带name的方法,name是类型信息。
name: 调用的方法名称
sig: 类型标签,见上面。
访问字段
静态字段
>ruby -rrjb -e "Rjb::import('java.lang.System').out.println('Just Another Ruby Hacker')"
Just Another Ruby Hacker
>
实例字段
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
绑定Ruby对象到java的接口
你可以把Ruby的对象绑定到java的接口上,只要这个对象有责任返回来自java世界的方法。
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): 绑定ruby对象到java 接口
obj, ruby对象
name, java的接口名称
return 绑定到特定接口的新对象。
在ruby中抛出java异常。
class Iterator
def hasNext()
true
end
def next()
Rjb::throw('java.util.NoSuchElementException', 'test exception')
end
end
这段代码抛出一个带“test exception”消息的NoSuchElementException异常,当调用者调用Iterator#next的时候
throw(classname, message)
抛出一个异常对象。
classname
可以抛出的类的名字
message
原因的描述
检查对象的类
rjb为每个实例增加了叫_classname的方法。 这个方法返回它的类的名称
obj#_classname
返回java类名。
例如
require 'rjb'
out = Rjb::import('java.lang.System').out
p out._classname
out.println('jarh')
result:
"java.io.PrintStream"
jarh
可以帮助指正这里英文错误么