RJava uses the JNI (Java Native Library) way to interoperate R and Java. This is the most common and intuitive way for me.
RCaller sends commands to R interpreter by creating a process for each single call. Then it handles the results as XML and parses it. It is the easiest and the most in-efficient way of calling R from Java. But it works.
And finally, Renjin, is a re-implementation of R for the Java Virtual Machine. I think, this will be the most rational way of calling R from Java because it is something like
Renjin,
is not for calling R from Java,
is for calling itself and maybe it can be said that: it is for calling java from java :),
for Java programmers who aimed to use R in their projects
So that is why I participated this project. External function calls are always make pain whatever the way you use.
Renjin is an R implementation in Java.
I think all these paragraphs tell the whole story.
How can we embed Renjin to our Java projects? Lets do something... But we have some requirements:
- renjin-core-0.1.2-SNAPSHOT.jar (Download from http://code.google.com/p/renjin/wiki/Downloads?tm=2)
- commons-vfs-1.0.jar (Part of apache commons)
- commons-logging-1.1.1.jar (Part of apache commons)
- guava-r07.jar (http://code.google.com/p/guava-libraries/downloads/list)
- commons-math-2.1.jar (Part of apache commons)
Ok. These are the renjin and required Jar files. Lets evaluate the R expression "x<-1:10" which creates a vector of integers from one to ten. Tracking the code is straightforward.
package renjincall; import java.io.StringReader; import r.lang.Context; import r.lang.SEXP; import r.parser.ParseOptions; import r.parser.ParseState; import r.parser.RLexer; import r.parser.RParser; import r.lang.EvalResult; public class RenjinCall { public RenjinCall() { Context topLevelContext = Context.newTopLevelContext(); try { topLevelContext.init(); } catch (Exception e) { } StringReader reader = new StringReader("x<-1:10\n"); ParseOptions options = ParseOptions.defaults(); ParseState state = new ParseState(); RLexer lexer = new RLexer(options, state, reader); RParser parser = new RParser(options, state, lexer); try { parser.parse(); } catch (Exception e) { System.out.println("Cannot parse: " + e.toString()); } SEXP result = parser.getResult(); System.out.println(result); } public static void main(String[] args) { new RenjinCall(); } }
We are initializing the library, creating the lexer and the parser and hadling the result as a SEXP. Finally we are printing the SEXP object (not itself, its String representation)
<-(x, :(1.0, 10.0))This is the parsed version of our "x<-1:10", it contains the same amount of information but it is a little bit different in form. Since we only parsed the content but it has not been evaluated. Track the code:
EvalResult eva = result.evaluate(topLevelContext, topLevelContext.getEnvironment()); System.out.println(eva.getExpression().toString());
Now, the output is
c(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
and this is the well known representation of R integer vectors. Of course printing the result in String format is not all the work. We would handle the elements of this array rather than print it. Lets do some work on it:
IntVector vector = (IntVector) eva.getExpression(); for (int i = 0; i < vector.length(); i++) { System.out.println( i + ". element of this vector is: " + vector.getElementAsInt(i) ); }
IntVector is defined in renjin core library and is for handling integer vectors. We simple used the .length() and .getElementAsInt() methods like using Java's ArrayList class. Finally the result is
0. element of this vector is: 1 1. element of this vector is: 2 2. element of this vector is: 3 3. element of this vector is: 4 4. element of this vector is: 5 5. element of this vector is: 6 6. element of this vector is: 7 7. element of this vector is: 8 8. element of this vector is: 9 9. element of this vector is: 10
It is nice, hah?