forked from jruby/jruby
-
Notifications
You must be signed in to change notification settings - Fork 0
JRubyAndJavaCodeExamples
pfussell edited this page Jan 6, 2011
·
9 revisions
» JRuby Project Wiki Home Page
Below are some code examples showing how to call JRuby from Java and how to call Java from JRuby.require "java" include_class "java.util.TreeSet" include_class "com.example.CallMe" include_class "com.example.ISpeaker" puts "Hello from ruby" set = TreeSet.new set.add "foo" set.add "Bar" set.add "baz" set.each { |v| puts "value: #{v}" } cm = CallMe.new cm.hello $globalCM.hello class CallJava include ISpeaker def initialize super @count = 0 end def say(msg) puts "Ruby saying #{msg}" end def addOne(from) # m.synchronize { @count += 1 puts "Now got #@count from #{from}" # } end end
package com.example; public interface ISpeaker { public void say(String msg); public void addOne(String from); }
package com.example; public class CallMe { String mName; public CallMe() { this("Default"); } public CallMe(String name) { mName = name; } public void hello() { System.out.println("Hello from "+mName); } public static void main(String []args) { System.out.println("Called main"); } }
package com.example; import org.apache.bsf.BSFManager; import org.apache.bsf.util.IOUtils; import org.jruby.Ruby; import org.jruby.javasupport.Java; import org.jruby.javasupport.JavaEmbedUtils; import org.jruby.javasupport.JavaUtil; import org.jruby.runtime.Block; import org.jruby.runtime.GlobalVariable; import org.jruby.runtime.builtin.IRubyObject; import java.io.FileReader; import java.io.IOException; /** * Example of how to: * 1. Use java objects in ruby * 2. Subclass/implement java objects in ruby * 3. Get ruby objects for use in java world * 4. Proxy ruby objects for normal use as java objects (interfaces/class) */ public class CallRuby { public static void main(String[] args) throws Exception { String dir = "/dclark/workspace/jrubytest/ruby/"; double[] deltas = new double[3]; for (int i = 0; i < 3; i++) { boolean useBSF = (i == 0); long start = System.currentTimeMillis(); if (useBSF) { //--- Initialise ruby BSFManager.registerScriptingEngine("ruby", "org.jruby.javasupport.bsf.JRubyEngine", new String[]{"rb"}); BSFManager manager = new BSFManager(); //--- Define a global variable CallMe javaCallMe = new CallMe("globalCallMeInJava"); manager.declareBean("globalCM", javaCallMe, javaCallMe.getClass()); //--- Load a ruby file manager.exec("ruby", "call_java.rb", -1, -1, getFileContents(dir + "call_java.rb")); //--- Make a new ruby object String expr = "CallJava.new"; ISpeaker ruby = (ISpeaker) manager.eval("ruby", "call_java.rb", -1, -1, expr); testMultiThreadsCallingRubyObject(ruby); } else { //--- Initialise ruby final Ruby runtime = Ruby.getDefaultInstance(); // Need the blank object so can get a nice runtime for the Java.staticMethods calls runtime.eval(runtime.parse("require \"java\"\nclass BlankForJva\nend\n", "BlankForJva.rb", runtime.getCurrentContext().getCurrentScope(), 0)); final IRubyObject blankRuby = runtime.evalScript("BlankForJva.new"); //--- Define a global variable CallMe javaCallMe = new CallMe("globalCallMeInJava"); IRubyObject globValue = JavaUtil.convertJavaToRuby(runtime, javaCallMe); // Wrap so that all methods are visible to ruby globValue = Java.java_to_ruby(blankRuby, globValue, Block.NULL_BLOCK); GlobalVariable globVar = new GlobalVariable(runtime, "$globalCM", globValue); runtime.defineVariable(globVar); //--- Load a ruby file runtime.eval(runtime.parse(getFileContents(dir + "call_java.rb"), "call_java.rb", runtime.getCurrentContext().getCurrentScope(), 0)); //--- Make a new ruby object String expr = "CallJava.new"; final IRubyObject rawRuby = runtime.evalScript(expr); ISpeaker ruby; if (i == 1) { // Standard wrapper using Java Proxies ruby = (ISpeaker) JavaEmbedUtils.rubyToJava(runtime, rawRuby, ISpeaker.class); } else { // Or manually wrap ruby object so can be used as the interface (can optionally add synchronization as required on methods) ruby = new ISpeaker() { public void addOne(String from) { // synchronized (rawRuby) { rawRuby.callMethod(runtime.getCurrentContext(), "addOne", JavaUtil.convertJavaToRuby(runtime, from)); // } } public void say(String msg) { rawRuby.callMethod(runtime.getCurrentContext(), "say", JavaUtil.convertJavaToRuby(runtime, msg)); } }; } testMultiThreadsCallingRubyObject(ruby); } long end = System.currentTimeMillis(); deltas[i] = (end - start) / 1000.0; } for (int i = 0; i < deltas.length; i++) { System.out.println("Took " + deltas[i] + " on pass " + i); } } private static String getFileContents(String filename) throws IOException { FileReader in = new FileReader(filename); return IOUtils.getStringFromReader(in); } public static void testMultiThreadsCallingRubyObject(final ISpeaker ruby) throws InterruptedException { Thread t1 = new Thread(new Runnable() { public void run() { for (int i = 0; i < 1000; i++) { ruby.addOne("t1"); } } }); Thread t2 = new Thread(new Runnable() { public void run() { for (int i = 0; i < 1000; i++) { ruby.addOne("t2"); } } }); t1.start(); t2.start(); t1.join(); t2.join(); ruby.addOne("end"); } }
Note: If you have only simple interface requirements, you can use the second method of proxying the ruby object to include method level synchronization.
Note: BSF calling does not preserve ruby stack traces (add an error to a script and run both ways using the code above).