Java and R
This article provides instructions on how to configure Java for use with R and the rJava
package. These instructions should be robust to Java patches and updates, which can be a source of problems for R code depending on rJava
. A system administrator should configure Java for each version of R installed on the servers supporting Workbench and Connect.
Alternatives to rJava
It is important to note that for some workflows, you can avoid the need to install rJava entirely.
Working with Excel files
We recommend the following packages for interacting with Excel:
Connecting to databases
Posit offers ODBC connectors for many popular databases, which you can use as an alternative to connecting to a database via JDBC. These drivers are available for Workbench, RStudio Desktop Pro, and Connect.
Setup Java support in R
If you are unable to implement an alternative to rJava
, these instructions describe how to configure R with Java support. These actions require root privileges and should be performed by a server administrator.
Overview
- Install Java JDK
- Set the
JAVA_HOME
environment variable - Reconfigure R to add Java support
You can have multiple versions of the JDK on your server to support multiple versions of R. Follow this procedure in full for each version of R that you are configuring.
Install Java JDK
Java JDK is the Software Development Kit (SDK) for Java. For R versions prior to 4.0, we recommend JDK 8. For R versions 4.0 or greater, install JDK 11 or later.
R Version | Ubuntu/Debian | RHEL/CentOS |
---|---|---|
R 3.x | sudo apt-get install openjdk-8-jdk |
sudo yum install java-1.8.0-openjdk-devel |
R 4.x | sudo apt-get install openjdk-11-jdk |
sudo yum install java-11-openjdk-devel |
Set JAVA_HOME
By default, when R is configured with Java, it will point to the default installation of Java and its specific minor version and patch level. If subsequent updates are made to the Java version, the R configuration will not find Java on the system, causing errors. To correct this, specify the JAVA_HOME
environment variable to a more stable folder containing the desired Java installation.
R Version | Ubuntu/Debian | RHEL/CentOS |
---|---|---|
R 3.x | export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64/ |
export JAVA_HOME=/usr/lib/jvm/jre-1.8.0-openjdk |
R 4.x | export JAVA_HOME=/usr/lib/jvm/java-11-openjdk-amd64/ |
export JAVA_HOME=/usr/lib/jvm/jre-11-openjdk/ |
Reconfigure R
To configure R to point to the desired Java installation, use the R CMD javareconf
command. It is recommended to execute this command explicitly with version of R you are seeking to configure, i.e.,
Terminal
$ sudo /opt/R/<R_VERSION>/R CMD javareconf
Example output of this command is shown below
Java interpreter : /usr/lib/jvm/jre-11-openjdk/bin/java
Java version : 11.0.14
Java home path : /usr/lib/jvm/jre-11-openjdk
Java compiler : /usr/lib/jvm/jre-11-openjdk/bin/javac
Java headers gen.:
Java archive tool: /usr/lib/jvm/jre-11-openjdk/bin/jar
trying to compile and link a JNI program
detected JNI cpp flags : -I$(JAVA_HOME)/include -I$(JAVA_HOME)/include/linux
detected JNI linker flags : -L$(JAVA_HOME)/lib/server -ljvm
gcc -std=gnu11 -I"/opt/R/4.1.2/lib/R/include" -DNDEBUG -I/usr/lib/jvm/jre-11-openjdk/include -I/usr/lib/jvm/jre-11-openjdk/include/linux -I/usr/local/include -fpic -g -O2 -c conftest.c -o conftest.o
gcc -std=gnu11 -shared -L/opt/R/4.1.2/lib/R/lib -L/usr/local/lib -o conftest.so conftest.o -L/usr/lib/jvm/jre-11-openjdk/lib/server -ljvm -L/opt/R/4.1.2/lib/R/lib -lR
JAVA_HOME : /usr/lib/jvm/jre-11-openjdk
Java library path: $(JAVA_HOME)/lib/server
JNI cpp flags : -I$(JAVA_HOME)/include -I$(JAVA_HOME)/include/linux
JNI linker flags : -L$(JAVA_HOME)/lib/server -ljvm
Updating Java configuration in /opt/R/4.1.2/lib/R
Done.
The javareconf
command will modify the R version’s /lib/R/etc/ldpaths
and /lib/R/etc/Makeconf
files, which specify the Java binaries and paths. These are specific to R, so the default version of Java outside of R will not change.
Additional Steps for Workbench
To this point, we have configured each version of R on the server to point to the desired version of Java, as specified in the /opt/R/<R_VERSION>/lib/R/etc/ldpaths
file. Workbench must be configured to read the ldpaths
configuration file in order to correctly detect the Java reconfiguration.
This configuration is set using the /etc/rstudio/r-versions
file, which allows you to specify extended information for a particular R version, e.g.,
/etc/rstudio/r-versions
Path: /opt/R/4.2.0
Script: /opt/R/4.2.0/lib/R/etc/ldpaths
Example
This example will describe in detail what is happening behind the scenes when Java is configured for R.
The example below is for CentOS 7 and R 4.1.2 installed according to the Posit documentation but can be generalized to other Linux distributions, R, and Java versions.
First, we install both OpenJDK 11 and 1.8.0 via
Terminal
$ yum install java-11-openjdk-devel
$ yum install java-1.8.0-openjdk-devel
Once those two versions are installed (exactly in the order as above), java -version
will report something like:
openjdk version "1.8.0_322"
OpenJDK Runtime Environment (build 1.8.0_322-b06)
OpenJDK 64-Bit Server VM (build 25.322-b06, mixed mode)
This means that the default version of Java on the system is Java 1.8.0
The minor version/patch level, e.g. the “_322-b06” can be different on your system. While the major version (1.8.0) and consequently the API does not change, bug fixes and security patches are applied as needed which triggers a change in the minor version/patch level.
This is also exactly the reason why we choose JAVA_HOME
to be /usr/lib/jvm/jre-11-openjdk/
which is an indirect symbolic link to /usr/lib/jvm/jre-11-openjdk-11.0.14.0.9-1.el7_9.x86_64
. The folder with the patch level versioning will change if the server is patched. The symbolic link however will stay unchanged. Hence access to Java from R will stay unchanged as well.
Now, as per the recommendation above, we configure R 4.1.2 with the java version in java-11-openjdk
. We set JAVA_HOME
:
Terminal
$ export JAVA_HOME=/usr/lib/jvm/jre-11-openjdk
and then reconfigure R:
Terminal
$ sudo /opt/R/4.1.2/bin/R CMD javareconf
Java interpreter : /usr/lib/jvm/jre-11-openjdk/bin/java
Java version : 11.0.14
Java home path : /usr/lib/jvm/jre-11-openjdk
Java compiler : /usr/lib/jvm/jre-11-openjdk/bin/javac
Java headers gen.:
Java archive tool: /usr/lib/jvm/jre-11-openjdk/bin/jar
trying to compile and link a JNI program
detected JNI cpp flags : -I$(JAVA_HOME)/include -I$(JAVA_HOME)/include/linux
detected JNI linker flags : -L$(JAVA_HOME)/lib/server -ljvm
gcc -std=gnu11 -I"/opt/R/4.1.2/lib/R/include" -DNDEBUG -I/usr/lib/jvm/jre-11-openjdk/include -I/usr/lib/jvm/jre-11-openjdk/include/linux -I/usr/local/include -fpic -g -O2 -c conftest.c -o conftest.o
gcc -std=gnu11 -shared -L/opt/R/4.1.2/lib/R/lib -L/usr/local/lib -o conftest.so conftest.o -L/usr/lib/jvm/jre-11-openjdk/lib/server -ljvm -L/opt/R/4.1.2/lib/R/lib -lR
JAVA_HOME : /usr/lib/jvm/jre-11-openjdk
Java library path: $(JAVA_HOME)/lib/server
JNI cpp flags : -I$(JAVA_HOME)/include -I$(JAVA_HOME)/include/linux
JNI linker flags : -L$(JAVA_HOME)/lib/server -ljvm
Updating Java configuration in /opt/R/4.1.2/lib/R
Done.
The two files in the R installation that have changed are etc/Makeconf
and etc/ldpaths
. If we look for any occurrence of JAVA
in both files we find
Terminal
# grep JAVA etc/Makeconf
JAVA = /usr/lib/jvm/jre-11-openjdk/bin/java
JAVAC = /usr/lib/jvm/jre-11-openjdk/bin/javac
JAVAH =
JAVA_HOME = /usr/lib/jvm/jre-11-openjdk
JAVA_CPPFLAGS = -I$(JAVA_HOME)/include -I$(JAVA_HOME)/include/linux
JAVA_LIBS = -L$(JAVA_HOME)/lib/server -ljvm
JAVA_LD_LIBRARY_PATH = $(JAVA_HOME)/lib/server
# grep JAVA etc/ldpaths
: ${JAVA_HOME=/usr/lib/jvm/jre-11-openjdk}
: ${R_JAVA_LD_LIBRARY_PATH=${JAVA_HOME}/lib/server}
Had we run R CMD javareconf
without specifying the Java version we were targeting, R would have been reconfigured to use Java 1.8 in a patch-level directory with the binaries in /usr/bin
:
Terminal
# grep JAVA etc/Makeconf
JAVA = /usr/bin/java
JAVAC = /usr/bin/javac
JAVAH = /usr/bin/javah
JAVA_HOME = /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.332.b09-1.el7_9.x86_64/jre
JAVA_CPPFLAGS = -I$(JAVA_HOME)/../include -I$(JAVA_HOME)/../include/linux
JAVA_LIBS = -L$(JAVA_HOME)/lib/amd64/server -ljvm
JAVA_LD_LIBRARY_PATH = $(JAVA_HOME)/lib/amd64/server
# grep JAVA etc/ldpaths
: ${JAVA_HOME=/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.332.b09-1.el7_9.x86_64/jre}
: ${R_JAVA_LD_LIBRARY_PATH=${JAVA_HOME}/lib/amd64/server}
Summary
In the example above, we have two versions of Java on the system. Java 1.8 is the default Java version on the operating system layer. Within R, OpenJDK 11 is the default Java version. Our solution now has two benefits:
- The default Java version on the operating system layer does not need to be the same version in R and can change independently from the R configuration.
- Java support in R is more resilient against further patches to OpenJDK 11 because:
- We rely on symbolic links to the current patch level of a given Java version that is used in R (e.g. OpenJDK 11 in our example) and not the direct installation directory with the patch level encoded into the directory name
- We do not use Java binaries linked into
/usr/bin
that always resemble the system default Java version but not necessarily the one that is configured in R