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

  1. Install Java JDK
  2. Set the JAVA_HOME environment variable
  3. 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

Note

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