CSC/ECE 517 Fall 2012/ch1 1w6 pp: Difference between revisions
(82 intermediate revisions by 2 users not shown) | |||
Line 1: | Line 1: | ||
<p>Mixing static and dynamic [http://en.wikipedia.org/wiki/Object_oriented Object Oriented] code helps us | <p>Mixing static and dynamic [http://en.wikipedia.org/wiki/Object_oriented Object Oriented] code helps us achieve a peaceful integration of static and dynamic aspects in the same language. This page will mention some of the difficulties which are observed when these two types of object orientation are mixed. We will then give a practical example of this using [http://en.wikipedia.org/wiki/JRuby JRuby]. JRuby is a [http://en.wikipedia.org/wiki/Programming_language programming language] which is a mix of [http://en.wikipedia.org/wiki/Java Java] and [http://en.wikipedia.org/wiki/Ruby Ruby]. We will cover the different implementations of JRuby with examples. </p> | ||
== Introduction == | == Introduction == | ||
Object oriented programming is a [http://en.wikipedia.org/wiki/Programming_paradigm programming paradigm] using "objects" – usually instances of a class – consisting of data fields and methods together with their interactions | Object oriented programming is a [http://en.wikipedia.org/wiki/Programming_paradigm programming paradigm] using "objects" – usually instances of a class – consisting of data fields and methods together with their interactions to design applications and computer programs. In static object orientation, this instantiation is static, that is the class to which an object belongs is defined before the execution of the code. This gives a strong binding of the objects, and ensures that the correct instance variables and methods are accessed by that object. In Dynamic object orientation, also known as interpreted object orientation, there is no fixed type. The type the object belongs to is determined during runtime, hence that gives additional flexibility. Static typing should be used where possible, dynamic typing when needed. | ||
== JRuby == | == JRuby == | ||
[http://en.wikipedia.org/wiki/JRuby JRuby] is the Ruby Programming Language on the [http://en.wikipedia.org/wiki/JVM JVM]. | [http://en.wikipedia.org/wiki/JRuby JRuby] is the Ruby Programming Language on the [http://en.wikipedia.org/wiki/JVM JVM]. | ||
Ruby is a reflective, dynamic, and interpreted object-oriented scripting language. JRuby is a Java programming language implementation of the Ruby language syntax with all the core libraries plus the standard libraries. With JRuby, you get all of the advantages of Ruby plus access to the full range of Java platform functionality. This can be achieved | Ruby is a reflective, dynamic, and interpreted object-oriented scripting language. JRuby is a Java programming language implementation of the Ruby language syntax with all the core libraries plus the standard libraries. With JRuby, you get all of the advantages of Ruby plus access to the full range of Java platform functionality. This can be achieved using the following two flavors.<br> | ||
* Driving Ruby from Java | * Driving Ruby from Java | ||
Line 28: | Line 17: | ||
* From a JRuby script, you can call the Java platform Math library to access its powerful computational capabilities or call the Java platform Swing library to display a dialog box that requires end-user input before allowing the script to proceed. <br> | * From a JRuby script, you can call the Java platform Math library to access its powerful computational capabilities or call the Java platform Swing library to display a dialog box that requires end-user input before allowing the script to proceed. <br> | ||
* You can use the [http://en.wikipedia.org/wiki/Scripting_for_the_Java_Platform JSR 223] Scripting APIs or the [http://en.wikipedia.org/wiki/Bean_Scripting_Framework Bean Scripting Framework (BSF)] APIs to call a JRuby script from within a Java application to, for example, invoke back-end processing scripts from a servlet to update or generate web content. <br> | * You can use the [http://en.wikipedia.org/wiki/Scripting_for_the_Java_Platform JSR 223] Scripting APIs or the [http://en.wikipedia.org/wiki/Bean_Scripting_Framework Bean Scripting Framework (BSF)] APIs to call a JRuby script from within a Java application to, for example, invoke back-end processing scripts from a servlet to update or generate web content. <br> | ||
== Difficulties in mixing static and dynamic object oriented code == | |||
There can be some issues in mixing static and dynamic object oriented code. | |||
* If the static object oriented code makes use of generics.<br> For example, in case we are using Java, the generic types are erased during compilation for backward compatibility. As a result for a dynamically types language like Ruby, there will be problems with type conversion.For example, if you have a Map<String,String>, it will be seen as a simple Map, and JRuby will not be able to determine the correct types using reflection.<br> | |||
* If you have a class name ambiguity between Java and Ruby.<br> In such a case, the class name will reference the Ruby construct within the Ruby code. For instance, if you import java.lang.Thread and then write JThread < Thread, JThread will in fact inherit the Ruby Thread object, not the Java Thread. The solution is to use the full Java Class name, such as: JThread < java.lang.Thread<br> | |||
* Java classes can't inherit from a JRuby class. Hopefully this feature will be added in the planned re-write of the Java integration layer in a future release of JRuby. | |||
* JRuby automatically binds the following names in the context of a class to the top-level Java packages: com, org, java, javax. This means that you can reference these packages without having to explicitly require or import them. This takes effect for all Ruby classes in an application where a require 'java' appears. If you do not want this behaviour for a specific class, you have to undefine it for that class. | |||
== Advantages of JRuby == | == Advantages of JRuby == | ||
Line 33: | Line 31: | ||
=== Advantages of JRuby over Ruby === | === Advantages of JRuby over Ruby === | ||
* With JRuby you get the best of both worlds: Ruby applications and libraries, plus Java libraries. | * With JRuby you get the best of both worlds: Ruby applications and libraries, plus Java libraries. <br> | ||
* Code can be fully compiled ahead of time or just in time. <br> | * Code can be fully compiled ahead of time or just in time. <br> | ||
* In addition to native you can access | * In addition to the native libraries you can access Java libraries with Ruby syntax (or Java syntax, if you want). <br> | ||
* | * JRuby runs faster than Ruby, except at startup.[http://blog.dhananjaynene.com/2008/07/performance-comparison-c-java-python-ruby-jython-jruby-groovy] | ||
=== Advantages of JRuby over Java === | === Advantages of JRuby over Java === | ||
* Ruby is | * Ruby is powerful. Ruby code is easy to understand. <br> | ||
* Ruby has features which are missing from Java <br> | * Ruby has the following good features which are missing from Java. <br> | ||
**[http://en.wikipedia.org/wiki/Closure_(computer_science) Closure (blocks)] <br> | **[http://en.wikipedia.org/wiki/Closure_(computer_science) Closure (blocks)] <br> | ||
**[http://en.wikipedia.org/wiki/Meta_programming Meta programming] <br> | **[http://en.wikipedia.org/wiki/Meta_programming Meta programming] <br> | ||
Line 47: | Line 45: | ||
**[http://en.wikipedia.org/wiki/Domain_Specific_Language Domain Specific Language] (DSL). | **[http://en.wikipedia.org/wiki/Domain_Specific_Language Domain Specific Language] (DSL). | ||
== JRuby | == JRuby Explained == | ||
JRuby | In addition to the advantages mentioned in the above section, some other features of JRuby are: | ||
*Reopening Java Classes | *Reopening Java Classes<br>In Ruby, classes are always open, which means that you can later add methods to existing classes. This also works with Java classes. This comes in handy when adding syntactic sugar like overloaded operators to Java classes, or other methods to make them behave more Ruby-like. Note that these additions will be visible only on the JRuby side. | ||
In Ruby, classes are always open, which means that you can later add methods to existing classes. This also works with Java classes. | *Mixing Java Interfaces <br> JRuby classes can now implement more than one Java interface. Since Java interfaces are mapped to modules in JRuby, you implement them not by subclassing, but by mixing them in. | ||
This comes in handy when adding syntactic sugar like overloaded operators to Java classes, or other methods to make them behave more Ruby-like. | *Exception handling <br> Native Java exceptions can be caught and thrown in Ruby code. | ||
Note that these additions will | *Synchronization <br> When interacting with Java APIs from JRuby, it is sometimes necessary to synchronize on an object for thread safety. To support this functionality, in JRuby, a synchronize method is provided on every wrapped Java object. | ||
*Mixing Java Interfaces | |||
JRuby classes can now implement more than one Java interface. Since Java interfaces are mapped to modules in JRuby, you implement them not by subclassing, but by mixing them in. | Let us see the two implementations of JRuby. | ||
*Exception handling | |||
Native Java exceptions can be caught and thrown in Ruby code. | |||
*Synchronization | |||
When interacting with Java APIs from JRuby, it is | |||
===<b> Driving Java from Ruby</b>=== | ===<b> Driving Java from Ruby</b>=== | ||
This involves calling Java methods from Ruby. This includes adding some | This involves calling Java methods from Ruby code. This includes adding some Java functionality in the Ruby code. The final code will be run on the JVM. Ruby code can load and interact with Java libraries. As a simple example we can use an ArrayList from Java and integrate it with the Ruby code as seen below: | ||
<pre> | <pre> | ||
Line 87: | Line 81: | ||
</pre> | </pre> | ||
One has to be careful in doing this as | One has to be careful in doing this as name conflicts in both Ruby and Java can result in losing the Ruby functionality. For example, if a File object is created using Java’s java.io.File class, then the Ruby constant File becomes useless. | ||
<pre> | <pre> | ||
Line 93: | Line 87: | ||
newfile = File.new("file.txt") | newfile = File.new("file.txt") | ||
</pre> | </pre> | ||
and then using | and then using: | ||
<pre> | <pre> | ||
Line 101: | Line 95: | ||
This will give the error - NoMethodError: private method `open' called for Java::JavaIo::File:Class | This will give the error - NoMethodError: private method `open' called for Java::JavaIo::File:Class | ||
This situation can be avoided by including the package in the module definition and then using that module scope to create using | This situation can be avoided by including the package in the module definition and then using that module scope to create a new file using the File object. | ||
<pre> | <pre> | ||
Line 108: | Line 102: | ||
JRuby will forward any option to the underlying Java runtime if you preface it with -J. | JRuby will forward any option to the underlying Java runtime if you preface it with -J. | ||
===<b>Driving Ruby from Java</b>=== | ===<b>Driving Ruby from Java</b>=== | ||
Line 152: | Line 108: | ||
====<b>Embedding JRuby</b>==== | ====<b>Embedding JRuby</b>==== | ||
Embed Core is the main embedding API that ships with JRuby. This API offers a great deal of interoperability. You can call a Ruby method, crunch the results in Java, and hand data back into Ruby. | Embed Core[https://github.com/jruby/jruby/wiki/DirectJRubyEmbedding] is the main embedding API that ships with JRuby. This API offers a great deal of interoperability. You can call a Ruby method, crunch the results in Java, and hand data back into Ruby. The following code shows an example of embedding Ruby in Java. | ||
<pre> | <pre> | ||
Line 174: | Line 130: | ||
</pre> | </pre> | ||
To run the above code you need to include jruby.jar in the classpath. This jar is present in the JRuby installation | To run the above code you need to include jruby.jar in the classpath. This jar is present in the lib folder of the JRuby installation directory. The above example outputs "3" as expected. | ||
====<b>JSR 223, Scripting for the Java Platform</b>==== | ====<b>JSR 223, Scripting for the Java Platform</b>==== | ||
This provides an API framework for calling scripting code from within a Java application and passing data between the application and the script. These features make it possible to combine existing scripts with Java applications and to extend a Java application with general-purpose scripts that other Java applications can also use. | This provides an API framework for calling scripting code from within a Java application and passing data between the application and the script. These features make it possible to combine existing scripts with Java applications and to extend a Java application with general-purpose scripts that other Java applications can also use. | ||
JSR 223 Scripting APIs are available in JDK 6 software, and by default, the APIs support the JavaScript programming language. | JSR 223 Scripting APIs are available in JDK 6 software, and by default, the APIs support the JavaScript programming language. The JSR 223 Scripting APIs can be used with any JSR 223-compliant scripting engine such as JRuby. | ||
The steps are: | |||
Java integration with Java 6 will be using the standard scripting API (JSR223). A JRuby scripting engine already exists and is located | *Java integration with Java 6 will be using the standard scripting API (JSR223). A JRuby scripting engine already exists and is located [https://scripting.dev.java.net here] | ||
Download and unzip the collection of jars from the documents and files section of the site (jsr223-engines.tar.gz or jsr223-engines.zip). | *Download and unzip the collection of jars from the documents and files section of the site (jsr223-engines.tar.gz or jsr223-engines.zip).Look in the uncompressed files for the jruby/build/jruby-engine.jar file. | ||
Look in the uncompressed files for the jruby/build/jruby-engine.jar file. | *Add this file to your classpath and then use the code below to access the engine. | ||
Add this file to your classpath and then use the code below to access the engine. | |||
<pre> | <pre> | ||
Line 205: | Line 160: | ||
} | } | ||
</pre> | </pre> | ||
The above program prints "Hello". | |||
====<b>The Bean Scripting Framework (BSF)</b>==== | ====<b>The Bean Scripting Framework (BSF)</b>==== | ||
Line 230: | Line 187: | ||
manager.exec("ruby", "(java)", 1, 1, "$label.setText(\"This is a test.\")"); | manager.exec("ruby", "(java)", 1, 1, "$label.setText(\"This is a test.\")"); | ||
</pre> | </pre> | ||
== Conversion of Types == | |||
When calling Java from JRuby, primitive Ruby types are converted to default boxed Java types. The table below shows this conversion. | |||
For example if we have a ruby method that returns a string object then we can convert it into a java.lang.String object on the Java side. The table shown below provides a quick overview of the mapping of types: | |||
{| style="background:#FFFFFB; margin-left: 4em;" border="1" cellpadding="4" cellspacing="0" | |||
|- | |||
| <b>Ruby Type</b>||<b> Java Type </b> | |||
|- | |||
| "foo" || java.lang.String | |||
|- | |||
| 1|| java.lang.Long | |||
|- | |||
| 1.0 || java.lang.Double | |||
|- | |||
| true, false|| java.lang.Boolean | |||
|- | |||
| 1|| java.math.BigInteger | |||
|} | |||
When primitive Java types are passed to JRuby they are converted to the following Ruby types: | |||
{| style="background:#FFFFFB; margin-left: 4em;" border="1" cellpadding="4" cellspacing="0" | |||
|- | |||
| <b>Java Type </b>||<b> Ruby Type </b> | |||
|- | |||
| public String || String | |||
|- | |||
| public byte || Fixnum | |||
|- | |||
| public short || Fixnum | |||
|- | |||
| public char || Fixnum | |||
|- | |||
| public int || Fixnum | |||
|- | |||
| public float || Float | |||
|- | |||
| public double|| Float | |||
|} | |||
== Difficulties with JRuby == | == Difficulties with JRuby == | ||
<b>Larger memory footprint and startup time</b> | <b>Larger memory footprint and startup time - Difficulty over Java. </b> | ||
A single JRuby instance needs more memory than a single Ruby instance, but in a typical production server environment with multiple mongrels, memory can be shared so that | A single JRuby instance needs more memory than a single Ruby instance, but in a typical production server environment with multiple mongrels, memory can be shared so that we can expect a lower or at least equal memory usage in total. JRuby’s startup time is higher than MRI, but once the JVM has “warmed up” after a few minutes, it usually runs faster than [http://en.wikipedia.org/wiki/Ruby_MRI MRI]. | ||
<b>No native C extension</b> | <b>No native C extension - Difficulty over Ruby.</b> | ||
Due to the nature of Java, it is impossible to run any native extension. So there are several gems that don’t work since they rely on a C extension. However, there’s ongoing effort to create alternative gems that are compatible to JRuby. E.g. mongrel uses a native C extension, but if you install the mongrel gem using JRuby, it automatically installs a java-enhanced version. | Due to the nature of Java, it is impossible to run any native extension. So there are several gems that don’t work since they rely on a C extension. However, there’s ongoing effort to create alternative gems that are compatible to JRuby. E.g. mongrel uses a native C extension, but if you install the mongrel gem using JRuby, it automatically installs a java-enhanced version. | ||
Line 243: | Line 244: | ||
<b>JRuby is not technically complete</b> | <b>JRuby is not technically complete</b> | ||
It’s told that there are cases where JRuby is not 100% compatible with MRI, | It’s told that there are cases where JRuby is not 100% compatible with MRI. However, big frameworks like Rails are tested with JRuby. | ||
== Conclusion == | == Conclusion == | ||
The JRuby interpreter combines Ruby's simplicity and ease of use with Java's extensive libraries and technologies, a potent blend that opens new possibilities for Ruby, Rails, and Java. Thus mixing static and dynamic code combines the power of dynamic languages with the stability of static languages. | The JRuby interpreter combines Ruby's simplicity and ease of use with Java's extensive libraries and technologies, a potent blend that opens new possibilities for Ruby, Rails, and Java. JRuby combines a lot of advantages of Java and Ruby by enabling us to reopen Java classes, mixing Java interfaces in Ruby, letting JRuby classes implement more than one Java interface by mixing the interfaces in the classes, catching the native Java exceptions and throwing them via Ruby code etc. There are three ways of calling Ruby from Java namely embedding JRuby, using JSR 223 and by using the bean scripting framework and this provides better flexibility to the programmer. Thus mixing static and dynamic code combines the power of dynamic languages with the stability of static languages. | ||
== References == | == References == | ||
#http://blog.dhananjaynene.com/2008/07/performance-comparison-c-java-python-ruby-jython-jruby-groovy<br> | |||
#http://www.javaworld.com/javaworld/jw-07-2006/jw-0717-ruby.html <br> | |||
#http://java.sun.com/developer/technicalArticles/scripting/jruby/ <br> | |||
#http://en.wikipedia.org/wiki/JRuby <br> | |||
#http://rubysource.com/learning-more-about-jruby-from-charles-nutter/ <br> | |||
#https://github.com/jruby/jruby/wiki/CallingJavaFromJRuby <br> | |||
#http://media.pragprog.com/titles/jruby/embed.pdf <br> | |||
#http://www.coderanch.com/t/461625/Ruby/JRuby-benefits <br> | |||
#http://zargony.com/2008/09/26/why-i-m-starting-to-like-jruby-even-though-i-dislike-java <br> | |||
#https://github.com/jruby/jruby/wiki/JavaIntegration#wiki-Java_6_using_JSR_223_Scripting <br> | |||
#https://github.com/jruby/jruby/wiki/DirectJRubyEmbedding <br> | |||
#Kutner, Joe (August 22, 2012), [http://research.microsoft.com/en-us/um/people/emeijer/Papers/RDL04Meijer.pdf Static Typing Where Possible, Dynamic Typing When Needed: The End of the Cold War Between Programming Languages]<br> | |||
== Further Reading == | == Further Reading == | ||
Charles O Nutter, Thomas Enebo, Nick Sieger, Ola Bini, and Ian Dees, Using JRuby:Bringing Ruby to Java, 2011 | Charles O Nutter, Thomas Enebo, Nick Sieger, Ola Bini, and Ian Dees, Using JRuby: Bringing Ruby to Java, 2011 |
Latest revision as of 00:19, 21 September 2012
Mixing static and dynamic Object Oriented code helps us achieve a peaceful integration of static and dynamic aspects in the same language. This page will mention some of the difficulties which are observed when these two types of object orientation are mixed. We will then give a practical example of this using JRuby. JRuby is a programming language which is a mix of Java and Ruby. We will cover the different implementations of JRuby with examples.
Introduction
Object oriented programming is a programming paradigm using "objects" – usually instances of a class – consisting of data fields and methods together with their interactions to design applications and computer programs. In static object orientation, this instantiation is static, that is the class to which an object belongs is defined before the execution of the code. This gives a strong binding of the objects, and ensures that the correct instance variables and methods are accessed by that object. In Dynamic object orientation, also known as interpreted object orientation, there is no fixed type. The type the object belongs to is determined during runtime, hence that gives additional flexibility. Static typing should be used where possible, dynamic typing when needed.
JRuby
JRuby is the Ruby Programming Language on the JVM.
Ruby is a reflective, dynamic, and interpreted object-oriented scripting language. JRuby is a Java programming language implementation of the Ruby language syntax with all the core libraries plus the standard libraries. With JRuby, you get all of the advantages of Ruby plus access to the full range of Java platform functionality. This can be achieved using the following two flavors.
- Driving Ruby from Java
- Driving Java from Ruby
Some examples where this integration can be done are:
- From a JRuby script, you can call the Java platform Math library to access its powerful computational capabilities or call the Java platform Swing library to display a dialog box that requires end-user input before allowing the script to proceed.
- You can use the JSR 223 Scripting APIs or the Bean Scripting Framework (BSF) APIs to call a JRuby script from within a Java application to, for example, invoke back-end processing scripts from a servlet to update or generate web content.
Difficulties in mixing static and dynamic object oriented code
There can be some issues in mixing static and dynamic object oriented code.
- If the static object oriented code makes use of generics.
For example, in case we are using Java, the generic types are erased during compilation for backward compatibility. As a result for a dynamically types language like Ruby, there will be problems with type conversion.For example, if you have a Map<String,String>, it will be seen as a simple Map, and JRuby will not be able to determine the correct types using reflection. - If you have a class name ambiguity between Java and Ruby.
In such a case, the class name will reference the Ruby construct within the Ruby code. For instance, if you import java.lang.Thread and then write JThread < Thread, JThread will in fact inherit the Ruby Thread object, not the Java Thread. The solution is to use the full Java Class name, such as: JThread < java.lang.Thread - Java classes can't inherit from a JRuby class. Hopefully this feature will be added in the planned re-write of the Java integration layer in a future release of JRuby.
- JRuby automatically binds the following names in the context of a class to the top-level Java packages: com, org, java, javax. This means that you can reference these packages without having to explicitly require or import them. This takes effect for all Ruby classes in an application where a require 'java' appears. If you do not want this behaviour for a specific class, you have to undefine it for that class.
Advantages of JRuby
Advantages of JRuby over Ruby
- With JRuby you get the best of both worlds: Ruby applications and libraries, plus Java libraries.
- Code can be fully compiled ahead of time or just in time.
- In addition to the native libraries you can access Java libraries with Ruby syntax (or Java syntax, if you want).
- JRuby runs faster than Ruby, except at startup.[1]
Advantages of JRuby over Java
- Ruby is powerful. Ruby code is easy to understand.
- Ruby has the following good features which are missing from Java.
JRuby Explained
In addition to the advantages mentioned in the above section, some other features of JRuby are:
- Reopening Java Classes
In Ruby, classes are always open, which means that you can later add methods to existing classes. This also works with Java classes. This comes in handy when adding syntactic sugar like overloaded operators to Java classes, or other methods to make them behave more Ruby-like. Note that these additions will be visible only on the JRuby side. - Mixing Java Interfaces
JRuby classes can now implement more than one Java interface. Since Java interfaces are mapped to modules in JRuby, you implement them not by subclassing, but by mixing them in. - Exception handling
Native Java exceptions can be caught and thrown in Ruby code. - Synchronization
When interacting with Java APIs from JRuby, it is sometimes necessary to synchronize on an object for thread safety. To support this functionality, in JRuby, a synchronize method is provided on every wrapped Java object.
Let us see the two implementations of JRuby.
Driving Java from Ruby
This involves calling Java methods from Ruby code. This includes adding some Java functionality in the Ruby code. The final code will be run on the JVM. Ruby code can load and interact with Java libraries. As a simple example we can use an ArrayList from Java and integrate it with the Ruby code as seen below:
require ‘java’ list = java.util.ArrayList.new list << ‘List of’ list << 3 list << :assorted_items list.each do |item| puts “#{item.class}: #{item}” end
Instead of just requiring a specific class you can also require the entire package. This can be done as follows:
module JavaLangDemo include_package "java.lang" # alternately, use the #import method import "java.lang" end
One has to be careful in doing this as name conflicts in both Ruby and Java can result in losing the Ruby functionality. For example, if a File object is created using Java’s java.io.File class, then the Ruby constant File becomes useless.
import java.io.File newfile = File.new("file.txt")
and then using:
File.open('README', 'r') {|f| puts f.readline }
This will give the error - NoMethodError: private method `open' called for Java::JavaIo::File:Class
This situation can be avoided by including the package in the module definition and then using that module scope to create a new file using the File object.
newfile = JavaIO::File.new("file.txt")
JRuby will forward any option to the underlying Java runtime if you preface it with -J.
Driving Ruby from Java
There are three ways for using the JRuby Interpreter from Java namely, Embedding JRuby, using JSR 223 and the Bean Scripting Framework.
Embedding JRuby
Embed Core[2] is the main embedding API that ships with JRuby. This API offers a great deal of interoperability. You can call a Ruby method, crunch the results in Java, and hand data back into Ruby. The following code shows an example of embedding Ruby in Java.
import java.util.ArrayList; import org.jruby.Ruby; import org.jruby.RubyRuntimeAdapter; import org.jruby.javasupport.JavaEmbedUtils; public class MyEmbedRubyExample { public static void main(String[] args) throws Exception { // Create runtime instance Ruby runtime = JavaEmbedUtils.initialize(new ArrayList()); RubyRuntimeAdapter evaler = JavaEmbedUtils.newRuntimeAdapter(); evaler.eval(runtime, "puts 1+2"); // Shutdown and terminate instance JavaEmbedUtils.terminate(runtime); } }
To run the above code you need to include jruby.jar in the classpath. This jar is present in the lib folder of the JRuby installation directory. The above example outputs "3" as expected.
JSR 223, Scripting for the Java Platform
This provides an API framework for calling scripting code from within a Java application and passing data between the application and the script. These features make it possible to combine existing scripts with Java applications and to extend a Java application with general-purpose scripts that other Java applications can also use. JSR 223 Scripting APIs are available in JDK 6 software, and by default, the APIs support the JavaScript programming language. The JSR 223 Scripting APIs can be used with any JSR 223-compliant scripting engine such as JRuby.
The steps are:
- Java integration with Java 6 will be using the standard scripting API (JSR223). A JRuby scripting engine already exists and is located here
- Download and unzip the collection of jars from the documents and files section of the site (jsr223-engines.tar.gz or jsr223-engines.zip).Look in the uncompressed files for the jruby/build/jruby-engine.jar file.
- Add this file to your classpath and then use the code below to access the engine.
import javax.script.*; public class jrubytry { public static void main(String[] args) throws Exception { ScriptEngineManager factory = new ScriptEngineManager(); // Create a JRuby engine. ScriptEngine engine = factory.getEngineByName("jruby"); // Evaluate JRuby code from string. try { engine.eval("puts('Hello')"); } catch (ScriptException exception) { exception.printStackTrace(); } } }
The above program prints "Hello".
The Bean Scripting Framework (BSF)
This is another way to call scripting code from within a Java application.
The Bean Scripting Framework, when used with JRuby, will allow you to conveniently to pass your own Java objects to your JRuby script. You can then use these objects in JRuby, and changes will affect your Java program directly. To run a JRuby script using BSF, you must first copy the BSF.jar file into your JAVA_HOME/lib/ext/ folder. Then, try the following:
import org.jruby.Ruby.*; import org.jruby.*; import org.jruby.javasupport.bsf.*; import org.apache.bsf.BSFException; import org.apache.bsf.BSFManager; {...} JLabel mylabel = new JLabel(); BSFManager.registerScriptingEngine("ruby", "org.jruby.javasupport.bsf.JRubyEngine", new String[] { "rb" }); BSFManager manager = new BSFManager(); /* Import an object using declareBean then you can access it in JRuby with $<name> */ manager.declareBean("label", mylabel, JFrame.class); manager.exec("ruby", "(java)", 1, 1, "$label.setText(\"This is a test.\")");
Conversion of Types
When calling Java from JRuby, primitive Ruby types are converted to default boxed Java types. The table below shows this conversion. For example if we have a ruby method that returns a string object then we can convert it into a java.lang.String object on the Java side. The table shown below provides a quick overview of the mapping of types:
Ruby Type | Java Type |
"foo" | java.lang.String |
1 | java.lang.Long |
1.0 | java.lang.Double |
true, false | java.lang.Boolean |
1 | java.math.BigInteger |
When primitive Java types are passed to JRuby they are converted to the following Ruby types:
Java Type | Ruby Type |
public String | String |
public byte | Fixnum |
public short | Fixnum |
public char | Fixnum |
public int | Fixnum |
public float | Float |
public double | Float |
Difficulties with JRuby
Larger memory footprint and startup time - Difficulty over Java.
A single JRuby instance needs more memory than a single Ruby instance, but in a typical production server environment with multiple mongrels, memory can be shared so that we can expect a lower or at least equal memory usage in total. JRuby’s startup time is higher than MRI, but once the JVM has “warmed up” after a few minutes, it usually runs faster than MRI.
No native C extension - Difficulty over Ruby.
Due to the nature of Java, it is impossible to run any native extension. So there are several gems that don’t work since they rely on a C extension. However, there’s ongoing effort to create alternative gems that are compatible to JRuby. E.g. mongrel uses a native C extension, but if you install the mongrel gem using JRuby, it automatically installs a java-enhanced version.
JRuby is not technically complete
It’s told that there are cases where JRuby is not 100% compatible with MRI. However, big frameworks like Rails are tested with JRuby.
Conclusion
The JRuby interpreter combines Ruby's simplicity and ease of use with Java's extensive libraries and technologies, a potent blend that opens new possibilities for Ruby, Rails, and Java. JRuby combines a lot of advantages of Java and Ruby by enabling us to reopen Java classes, mixing Java interfaces in Ruby, letting JRuby classes implement more than one Java interface by mixing the interfaces in the classes, catching the native Java exceptions and throwing them via Ruby code etc. There are three ways of calling Ruby from Java namely embedding JRuby, using JSR 223 and by using the bean scripting framework and this provides better flexibility to the programmer. Thus mixing static and dynamic code combines the power of dynamic languages with the stability of static languages.
References
- http://blog.dhananjaynene.com/2008/07/performance-comparison-c-java-python-ruby-jython-jruby-groovy
- http://www.javaworld.com/javaworld/jw-07-2006/jw-0717-ruby.html
- http://java.sun.com/developer/technicalArticles/scripting/jruby/
- http://en.wikipedia.org/wiki/JRuby
- http://rubysource.com/learning-more-about-jruby-from-charles-nutter/
- https://github.com/jruby/jruby/wiki/CallingJavaFromJRuby
- http://media.pragprog.com/titles/jruby/embed.pdf
- http://www.coderanch.com/t/461625/Ruby/JRuby-benefits
- http://zargony.com/2008/09/26/why-i-m-starting-to-like-jruby-even-though-i-dislike-java
- https://github.com/jruby/jruby/wiki/JavaIntegration#wiki-Java_6_using_JSR_223_Scripting
- https://github.com/jruby/jruby/wiki/DirectJRubyEmbedding
- Kutner, Joe (August 22, 2012), Static Typing Where Possible, Dynamic Typing When Needed: The End of the Cold War Between Programming Languages
Further Reading
Charles O Nutter, Thomas Enebo, Nick Sieger, Ola Bini, and Ian Dees, Using JRuby: Bringing Ruby to Java, 2011