◀Table of Contents
Interoperability with Java
The GraalVM R runtime provides the built-in interoperability with Java.
Java class objects can be obtained via java.type(...)
.
In order to run R with the Java interoperability features, the R
or Rscript
commands have to be started with the --jvm
option.
R --jvm
Note: All of the following examples are meant to be executed in the R REPL; no additional Java dependencies are necessary.
- The standard
new
function interprets String arguments as a Java class if such class exists. new
also accepts Java types returned fromjava.type
.- The fields and methods of Java objects can be accessed using the
$
operator. - Additionally, you can use
awt(...)
to open an R drawing device directly on a Java Graphics surface. For more details see Java Graphics Interoperability.
The following example creates a new Java BufferedImage
object, plots random data to it using R’s grid
package,
and shows an image in a window using Java’s AWT
framework.
Note that you must start the R script with --jvm
to have access to Java interoperability.
library(grid)
openJavaWindow <- function () {
# create image and register graphics
imageClass <- java.type('java.awt.image.BufferedImage')
image <- new(imageClass, 450, 450, imageClass$TYPE_INT_RGB);
graphics <- image$getGraphics()
graphics$setBackground(java.type('java.awt.Color')$white);
grDevices:::awt(image$getWidth(), image$getHeight(), graphics)
# draw image
grid.newpage()
pushViewport(plotViewport(margins = c(5.1, 4.1, 4.1, 2.1)))
grid.xaxis(); grid.yaxis()
grid.points(x = runif(10, 0, 1), y = runif(10, 0, 1),
size = unit(0.01, "npc"))
# open frame with image
imageIcon <- new("javax.swing.ImageIcon", image)
label <- new("javax.swing.JLabel", imageIcon)
panel <- new("javax.swing.JPanel")
panel$add(label)
frame <- new("javax.swing.JFrame")
frame$setMinimumSize(new("java.awt.Dimension",
image$getWidth(), image$getHeight()))
frame$add(panel)
frame$setVisible(T)
while (frame$isVisible()) Sys.sleep(1)
}
openJavaWindow()
GraalVM’s R runtime provides its own rJava-compatible replacement package available at GitHub, which can be installed using:
R -e "install.fastr.packages('rJava')"
In order for third party Java libraries to be accessed, they have to be placed on R’s class path:
> java.addToClasspath("/foo/bar.jar")
> java.addToClasspath(c("/foo/bar.jar", "/foo/bar2.jar"))
Getting a Java Class
The access to a Java type is achieved by providing a fully qualified class name to the java.type
function:
> calendarClass <- java.type('java.util.GregorianCalendar')
The returned value is a polyglot object representing a Java type.
The respective Java class is then available through the class
property:
> calendarClass$class
The same works also for static class members:
> calendarClass$getInstance()
Every requested class has to be on the R classpath.
The JDK classes, like GregorianCalendar
used above, work out of the box.
Creating a New Java Object
A new Java object can be created by providing a Java type to the new
function:
> calendar <- new(calendarClass)
It is also possible to pass over additional constructor arguments:
> calendar <- new(calendarClass, year=2042L, moth=3L, day=1L)
Alternately, you can use just a class name:
calendar <- new("java.util.GregorianCalendar")
calendar <- new("java.util.GregorianCalendar", year=2042L, moth=3L, day=1L)
Accessing Fields and Methods
The access to static and instance fields and methods is provided by the $
and [
operators.
To access Java fields:
> calendarClass$SUNDAY
> calendarClass["SUNDAY"]
To invoke Java methods:
> currentTime <- calendar$getTime()
> currentTime["toString"]()
> calendar$setTime(currentTime)
Polyglot objects returned from a field or method, or created via new
, are either automatically converted into corresponding R values or they live on as polyglot objects in the GraalVM R runtime.
If necessary, they can be passed over to Java:
> cet <- java.type("java.util.TimeZone")$getTimeZone("CET")
> cetCalendar <- new(calendarClass, cet)
Handling of Java Primitives
The returned Java primitives, primitive wrappers, and String instances are automatically converted into corresponding R values and map as follows:
- R
integer
values map directly to Javaint
/Integer
- R
numeric
to Javadouble
/Double
- R
logical
to Javaboolean
/Boolean
- R
character
to JavaString
- If necessary R
integer
anddouble
are converted to the expected Java type
Inspecting Polyglot Objects
The names
function can be used to obtain a list of instance and static members from a polyglot Java object or Java class:
> names(calendar)
> names(calendarClass)
Code completion works as well:
> calendar$a<TAB>
Working with Java Arrays
The need for Java arrays appears when they have to be passed over to java
as arguments.
You can create an array by creating an array class and instantiating an array from it:
> arrayClass <- java.type('int[]')
> intArray <- new(arrayClass, 3)
The component type names of primitive arrays are boolean
, byte
, char
, double
, float
, int
, long
,
and short
– the same as in each particular primitive wrapper TYPE constant (see, e.g., Integer.TYPE.getName()
).
Note that it is possible to pass an R vector into a Java method in case the expected Java array is of a primitive component type or String.
Then, the conversion happens automatically in the background.
> integerArray <- new(java.type('java.lang.Integer[]'), 3L)
> integer2DimArray <- new('java.lang.Integer[][]', c(2L, 3L))
> stringArray <- new(java.type('java.lang.String[]'), 3L)
The access to array elements is provided by the [
operator:
> stringArray[1] <- 'a'
> string2DimArray[1,1] <- 'a'
> element <- stringArray[1]
> element <- string2DimArray[1,1]
Converting Java Arrays into R Objects
Unlike Java primitives or their wrappers, Java arrays are not automatically converted into an R vector. Nevertheless, when appropriate, they can be handled by R builtin functions the same way as native R objects:
> sapply(intArray, function(e) { e })
> length(stringArray)
> length(string2DimArray[1])
Explicit Java Array Conversion
A Java array conversion can be done explicitly by providing a Java array to the as.vector
function:
> intVec <- as.vector(intArray)
Arrays having a Java primitive component type are converted into an R vector. Otherwise a list containing the array elements is created:
> characterVector <- as.character(intArray)
> logicalVector <- as.logical(intArray)
> ...
Java Iterable Interface
When appropriate, Java objects implementing java.lang.Iterable
are handled in the same way as Java arrays when passed as arguments to functions:
> javaList <- new(java.type('java.util.ArrayList'))
> javaList$add(0);
> javaList$add(1)
> length(javaList)
> as.integer(javaList)
> as.logical(javaList)
Compatibility with rJava
The GraalVM R runtime comes with an rJava compatibility layer based on the Java interoperability features. Most of the officially documented rJava functions are supported. For more information, see the rJava CRAN documentation.
- You can install the GraalVM R runtime’s
rJava
replacement usinginstall.packages("rJava")
. Theinstall.packages
function in R has special handling for some packages, includingrJava
, and it downloads rJava from the source repository on GitHub instead of from MRAN. - As with any other R package, before executing any rJava functions, the package has to be loaded first:
> library(rJava)
Supported rJava features:
- The
$
and[
operators work the same as described above.
Java Graphics Interoperability
GraalVM R runtime’s graphics subsystem is mostly compatible with GNU-R’s graphics subsystem, i.e., most of the functions provided by grid
and graphics
base packages are supported.
See Reference of GNU-R’s graphical subsystem.
Aside from all the GNU-R graphics functionality, GraalVM R runtime provides an additional awt
device and functions tailored to manipulate the SVG device: svg.off
and sv.string
.
The awt
device is based on the Java Graphics2D
object and users can pass it to their own Graphics2D
object instance when opening the device using the awt
function, as shown in the Java interop example.
When the Graphics2D
object is not provided to awt
, it opens a new window similar to X11
.
The SVG device is demonstrated in the following code sample:
library(lattice)
svg()
mtcars$cars <- rownames(mtcars)
print(barchart(cars~mpg, data=mtcars))
svgCode <- svg.off()
cat(svgCode)
To learn more, see the ?functionName
syntax.