Search code examples
rrjava

Replicating a java -jar execution through rJava


I have a java file that I would normally execute by doing

java -jar jarname.jar arguments

I want to be able to run this file from R in the most system agnostic way possible. My current pipeline partially relies on rJava do identify JAVA_HOME and run the jar by doing

# path for the example file below
pathToJar = 'pdftk-java.jar'
# start up java session
rJava::.jinit()
# find JAVA_HOME
javaPath = rJava::.jcall( 'java/lang/System', 'S', 'getProperty', 'java.home' )
# get all java files
javaFiles = list.files(javaPath,recursive = TRUE,full.names = TRUE)
# find java command
java = javaFiles[grepl('/java($|\\.exe)',javaFiles)]
# run the jar using system
system(glue::glue('{shQuote(java)} -jar {shQuote(pathToJar)} arguments'))

This does work fine but I was wondering if there was a reliable way to replicate execution of a jar through rJava itself. I want to do this because

  • I want to avoid any possible system dependent issues when finding the java command from JAVA_HOME
  • I already started an rJava session just to get the JAVA_HOME. I might as well use it since .jinit isn't undoable
  • I not that familiar with what calling a jar through -jar does and I am curious. Can it be done in a jar independent way? If not what should I look for in the code to know how to do this.

This is the file in I am working with. Taken from https://gitlab.com/pdftk-java/pdftk/tree/master


Solution

  • Executing JAR file is (essentially) running class file that is embedded inside JAR.

    Instead of calling system and executing it as external application, you can do following:

    • make sure to add your JAR file to CLASSPATH
    rJava::.jaddClassPath(pathToJar)
    
    • check inside JAR file what is the main class. Look into META-INF/MANIFEST.MF file to identify the main class. (In this case com.gitlab.pdftk_java.pdftk)
    • instantiate class inside R.
    newObj = rJava::.jnew('com/gitlab/pdftk_java/pdftk')
    

    Update

    Running JAR file (calling main method of Main-class) is the same things as calling any other method inside Java based class. Please note that main method takes array of Strings as argument. Take a look here for sample: http://www.owsiak.org/running-jar-file-from-r-using-rjava-without-spawning-new-process/

    newObj$main(rJava::.jarray('--version'))
    

    For this specific case if you look at the source code for this class, you'll see that it terminates the session

      public static void main(String[] args) {
        System.exit(main_noexit(args));
      }
    

    This will also terminate your R session. Since all main function does it to call main_noexit then exit, you can replace main with main_noexit in the code above.

    newObj$main_noexit(rJava::.jarray('--version'))