The package rJava provides an easy to use mechanism to call Java objects and methods from R. This page will show you how to build, inspect, and manipulate Java objects without leaving the comfort of R. Particular focus will be paid to GUI objects.
Java is an object oriented language, meaning that almost everything is an object, and all functions (i.e. methods) are linked to objects. This is in contrast to R, which is primarily a function oriented language.
A class is a template used to create a specific type of object. For example I might have a class called Chair
. This class is not an object it's self, but rather contains the recipe for creating a chair. This recipe is called a constructor, and when called creates a Chair
object. It can be called many times to create a series of chairs (e.g. this chair, and that chair over there). Each one of these chairs is called an 'instance of' the original Chair
class.
Classes can also be specific subtypes of other Classes. For example, our Chair
class might be a subtype of the Furniture
class, because all Chairs
are Furniture
. So when we create a new Chair
object, it is also a Furniture
object.
Functions are called methods in Java, and are tethered to a specific class. Methods can only be used with objects of their own class. For example, a Cheetah
class might have a method run
which would make the cat run, but we wouldn't be able to call that method to make a Chair
run. methods can be called on subclasses though, so I would be able call a Furniture
method on a Chair
.
A class can also have methods are called on the class (not an instance), and which don't require an instance to run. These are called 'static methods' and can be called using the class even if no objects have been created by that class. For example, our Cheetah
class might have a method getPopulation
which would return the number of Cheetah
s in the wild (i.e. the number of instances). This method relates to Cheetah
s, but doesn't relate to any specific Cheetah
, so it is a static method.
Hopefully the above sounded very familiar to you. R has an object system similar to Java called S4. Though you don't need to know to much about it, we will be using the S4 object system to work with Java classes and objects.
Lets start by making a JDialog
object. JDialog
is a class used to make a dialog window, and is a part of the Swing GUI library.
The first thing we need to do is create a variable representing the class. This can be done with the J
function, which takes as an argument the class location, and returns a reference to that location (an S4 object of class jclassName). JDialog is located in the javax.swing Java package, so we simply need to call.
> JDialog <- J("javax.swing.JDialog") > print(JDialog) [1] "Java-Class-Name: javax.swing.JDialog"
Now that we have a reference to the JDialog
class, we can a new object by calling the new
function. new
takes as its first argument a jclassName
(e.g. JDialog
), and any further arguments are passed to the JDialog
constructor.
> myDialog <- new(JDialog)
myDialog
is now a reference (of S4 class jobjRef
) to an instance of JDialog
. We don't see anything yet, because we have not made the dialog visible. There is a JDialog
method called setVisible
which we can use to make the dialog visible. Set visible takes a boolean (true/false) as a parameter. rJava transparently takes care of the conversion between R logical and Java boolean. We will go into conversions later on.
> myDialog$setVisible(TRUE)
You should now see a small empty dialog window.
"But wait" you say! This all seems sort of magical.
setVisible
Well, number 1 is sort of hard. Java is a big language, with lots of libraries and packages. If you are looking for something in plain Java, you can start by looking through the Java API JavaDocs. For things related to JGR, rJava and Deducer, you can look through the nightly generated Java docs.
Numbers 2 and 3 are easier to answer. we can list the available constructors with the .jconstructors
function.
> .jconstructors(JDialog) [1] "public javax.swing.JDialog(java.awt.Frame) throws java.awt.HeadlessException" [2] "public javax.swing.JDialog(java.awt.Frame,boolean) throws java.awt.HeadlessException" [3] "public javax.swing.JDialog(java.awt.Frame,java.lang.String) throws java.awt.HeadlessException" [4] "public javax.swing.JDialog(java.awt.Frame,java.lang.String,boolean) throws java.awt.HeadlessException" [5] "public javax.swing.JDialog(java.awt.Frame,java.lang.String,boolean,java.awt.GraphicsConfiguration)" [6] "public javax.swing.JDialog() throws java.awt.HeadlessException" [7] "public javax.swing.JDialog(java.awt.Dialog,boolean) throws java.awt.HeadlessException" [8] "public javax.swing.JDialog(java.awt.Dialog,java.lang.String) throws java.awt.HeadlessException" [9] "public javax.swing.JDialog(java.awt.Dialog,java.lang.String,boolean) throws java.awt.HeadlessException" [10] "public javax.swing.JDialog(java.awt.Dialog,java.lang.String,boolean,java.awt.GraphicsConfiguration) throws java.awt.HeadlessException" [11] "public javax.swing.JDialog(java.awt.Dialog) throws java.awt.HeadlessException"
We can see that previously we called constructor number 6, which takes no arguments. Additionally a JDialog
can be created with parameters representing a parent window (Dialog
or Frame
), a boolean representing whether the dialog is modal (blocking), and/or a String title. It can also take a graphics configuration, but it is rare that you would ever want to do that. So any of the follow commands can make a JDialog:
> JFrame <- J("javax.swing.JFrame") > aFrame <- new(JFrame) > anotherDialog <- new(JDialog,aFrame) > anotherDialog <- new(JDialog,aFrame,TRUE) > anotherDialog <- new(JDialog,aFrame,"title") > anotherDialog <- new(JDialog,aFrame,"title",FALSE) > anotherDialog <- new(JDialog) > anotherDialog <- new(JDialog,myDialog) > anotherDialog <- new(JDialog,myDialog,"title") > anotherDialog <- new(JDialog,myDialog,"title",TRUE)
To look up what methods are available we use the .jmethods
function.
> .jmethods(myDialog) [1] "public void javax.swing.JDialog.remove(java.awt.Component)" [2] "public void javax.swing.JDialog.update(java.awt.Graphics)" [3] "public javax.accessibility.AccessibleContext javax.swing.JDialog.getAccessibleContext()" [4] "public void javax.swing.JDialog.setLayout(java.awt.LayoutManager)" [5] "public javax.swing.JRootPane javax.swing.JDialog.getRootPane()" [6] "public void javax.swing.JDialog.setContentPane(java.awt.Container)" [7] "public java.awt.Container javax.swing.JDialog.getContentPane()" [8] "public void javax.swing.JDialog.setLayeredPane(javax.swing.JLayeredPane)" [9] "public javax.swing.JLayeredPane javax.swing.JDialog.getLayeredPane()" [10] "public void javax.swing.JDialog.setGlassPane(java.awt.Component)" [11] "public java.awt.Component javax.swing.JDialog.getGlassPane()" [12] "public void javax.swing.JDialog.setDefaultCloseOperation(int)" [13] "public int javax.swing.JDialog.getDefaultCloseOperation()" [14] "public void javax.swing.JDialog.setJMenuBar(javax.swing.JMenuBar)" [15] "public javax.swing.JMenuBar javax.swing.JDialog.getJMenuBar()" [16] "public static void javax.swing.JDialog.setDefaultLookAndFeelDecorated(boolean)" [17] "public static boolean javax.swing.JDialog.isDefaultLookAndFeelDecorated()" ... ... ...
The first 17 of 297 methods are displayed above.
We can also view the publicly accessible fields of an object.
> .jfields(myDialog) [1] "public static final int javax.swing.WindowConstants.DO_NOTHING_ON_CLOSE" [2] "public static final int javax.swing.WindowConstants.HIDE_ON_CLOSE" [3] "public static final int javax.swing.WindowConstants.DISPOSE_ON_CLOSE" [4] "public static final int javax.swing.WindowConstants.EXIT_ON_CLOSE" [5] "public static final float java.awt.Component.TOP_ALIGNMENT" [6] "public static final float java.awt.Component.CENTER_ALIGNMENT" [7] "public static final float java.awt.Component.BOTTOM_ALIGNMENT" [8] "public static final float java.awt.Component.LEFT_ALIGNMENT" [9] "public static final float java.awt.Component.RIGHT_ALIGNMENT" [10] "public static final int java.awt.image.ImageObserver.WIDTH" [11] "public static final int java.awt.image.ImageObserver.HEIGHT" [12] "public static final int java.awt.image.ImageObserver.PROPERTIES" [13] "public static final int java.awt.image.ImageObserver.SOMEBITS" [14] "public static final int java.awt.image.ImageObserver.FRAMEBITS" [15] "public static final int java.awt.image.ImageObserver.ALLBITS" [16] "public static final int java.awt.image.ImageObserver.ERROR" [17] "public static final int java.awt.image.ImageObserver.ABORT"
We have already seen how to call the setVisible
method on out JDialog
. Calling other functions is similar. Our Dialog is pretty small right now. In fact, its size is 0. Lets give it some length and width, as well as a title.
> myDialog <- new(JDialog) > myDialog$setTitle("cool dialog") > myDialog$setSize(200L,500L) > > JLabel <- J("javax.swing.JLabel") > label <- new(JLabel,"Hi there, I'm a label") > myDialog$add(label) [1] "Java-Object{javax.swing.JLabel[,0,0,0x0,invalid,alignmentX=0.0,alignmentY=0.0,border=,flags=8388608,maximumSize=,minimumSize=,preferredSize=,defaultIcon=,disabledIcon=,horizontalAlignment=LEADING,horizontalTextPosition=TRAILING,iconTextGap=4,labelFor=,text=Hi there, I'm a label,verticalAlignment=CENTER,verticalTextPosition=CENTER]}" > > > myDialog$setVisible(TRUE) > myDialog$isVisible() [1] TRUE
You should now see a window 200 pixels wide and 500 pixels long titled "cool dialog." We've also added a text label to the content of the window. Notice that we used 200L
for the argument to setSize
. This is because the L
in R indicates that the number is an integer. Otherwise it would be numeric, which would then be converted to a Java double which the method doesn't understand.
Static methods can be called either on the class or an object, though it is recommended that the class be used.
> JDialog$isDefaultLookAndFeelDecorated() [1] FALSE
Fields (variables specific to a particular Java class or object) can also be accessed in a natural way.
> JDialog$EXIT_ON_CLOSE [1] 3
You may have noticed that we didn't actually pass any Frame
s or Dialog
s to the constructor in the .jconstructors
example above. Rather we gave it JFrame
s and JDialog
s. This is okay because they are subclasses of Frame
and Dialog
. We can check this using the instanceof
operator
> myDialog %instanceof% J("java.awt.Dialog") [1] TRUE > aFrame %instanceof% J("java.awt.Frame") [1] TRUE
rJava automatically takes care of the class conversions (called casting) without any need for you to worry about it. Indeed, it works the other way too. If a java method's signature says that it returns an object of class Frame
, but the object is actually a JFrame
, it is automatically promoted to a JFrame
and can be used as such. In some ways this could be considered an improvement on Java which normally requires you to handle the casting yourself.
Some R data types can be automatically converted to Java types when given to a method or constructor.
R vector (length>1) | Java |
---|---|
numeric | double[] |
integer | int[] |
character | java.lang.String[] |
logical | boolean[] |
R vector (length==1) | Java |
numeric | double |
integer | int |
character | java.lang.String |
logical | boolean |
An R object can be converted to other basic Java data types with .jfloat
, .jlong
, .jbyte
, .jchar
and .jshort
. If an R vector of length 1 needs to be passed as an array, simply wrap it in a .jarray
call.
> .jfloat(1) An object of class "jfloat" [1] 1 > .jlong(1) An object of class "jlong" [1] 1 > .jbyte(1) An object of class "jbyte" [1] 1 > .jchar(1) An object of class "jchar" [1] 1 > .jshort(1) An object of class "jshort" [1] 1 > .jarray(1) [1] "Java-Array-Object[D:[D@287a3"
You can do quite a bit with the above. A good place to start if/when you run into trouble is the rJava Documentation. If that fails and it is an rJava related problem, try the mailing list.