Anirudh Kumar Agarwal
Anirudh Kumar Agarwal

Reputation: 31

Running jar built using Maven causes "java.lang.NoClassDefFoundError: org/rosuda/JRI/Rengine" error

I am trying to build a JAR library that can invoke R code. I basically want this jar to be capable enough to be able to run on any machine that has support for running jar executables(No need of seperate R software). For this I am using Maven. I am able to compile and create a jar without any errors. However, when I run it, I am unable to yield successful results.

This is my java code

package com.company.analytics.timeseries;

import org.rosuda.JRI.REXP;
import org.rosuda.JRI.Rengine;

public class App {
    public static void main(String[] args) {
        System.out.println("Creating Rengine (with arguments)");
        String[] Rargs = { "--vanilla" };
        Rengine re = new Rengine(Rargs, false, null);
        System.out.println("Rengine created, waiting for R");
        if (!re.waitForR()) {
            System.out.println("Cannot load R");
            return;
        }
        System.out.println("Done.");
    }
}

This is my pom.xml file

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.company.analytics</groupId>
  <artifactId>timeseries</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>jar</packaging>

  <name>timeseries</name>
  <url>http://maven.apache.org</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.nuiton.thirdparty</groupId>
      <artifactId>JRI</artifactId>
      <version>RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.rosuda.REngine</groupId>
      <artifactId>REngine</artifactId>
      <version>2.1.0</version>
    </dependency>
  </dependencies>

  <repositories>
    <repository>
      <id>central</id>
      <name>Maven Central</name>
      <url>http://repo1.maven.org/maven2</url>
    </repository>
  </repositories>

</project>

I used mvn clean and then mvn package to create the jar file.

A JAR file of 4KB is created in C:\MVN\project\analytics\timeseries\target. Thern, from the command line on Windows, when I run execute this jar file, I get the following error

C:\MVN\project\analytics\timeseries\target\classes>java com.company.analytics.timeseries.App

Creating Rengine (with arguments)

Exception in thread "main" java.lang.NoClassDefFoundError: org/rosuda/JRI/Rengine

    at com.company.analytics.timeseries.App.main(App.java:10)
Caused by: java.lang.ClassNotFoundException: org.rosuda.JRI.Rengine
        at java.net.URLClassLoader.findClass(Unknown Source)
        at java.lang.ClassLoader.loadClass(Unknown Source)
        at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
        at java.lang.ClassLoader.loadClass(Unknown Source)
        ... 1 more

I am trying to figure out what mistake am I committing. I tried to find answers by googling, but I couldn't fix it.

Upvotes: 3

Views: 2127

Answers (3)

kian
kian

Reputation: 55

Since I've been smashing my head against this for a day now and I'll likely forget in the future and reference this page - per what Gergely Basco's suggests in an above comment, strictly speaking both R and rJava need to be installed on the machine in order to resolve the Cannot find JRI native library! issue when instantiating your org.rosuda.REngine.REngine object, and this cannot be done exclusively by way of adding the JRIEngine dependency in your pom.xml (bummer).

Steps (for how I'm doing it anyway for my later image):

  1. Install Brew (I just happen to be using Brew for other dependencies)

     /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
    
  2. Install R using brew:

    brew tap homebrew/science
    brew install R
    
  3. Install rJava with R (takes a bit of compile time, grab a coffee)

    install.packages("rJava")
    
  4. add rJava/jri to java.library.path classpath, add R_HOME to environment variables (where you installed R - in my case, where Brew installed it). Note that if you're trying to run this in your IDE(I'm running IDEA16), it won't inherit the path you set in ~/.bash_profile, you need to set it in your run configuration.

     -Djava.library.path="/usr/local/lib/R/3.3/site-library/rJava/jri/
     R_HOME=/usr/local/Cellar/r/3.3.1_2/R.framework/Resources
    
  5. Ensure maven has dependency for JRIEngine in pom.xml

    <dependency>
        <groupId>com.github.lucarosellini.rJava</groupId>
        <artifactId>JRIEngine</artifactId>
        <version>0.9-7</version>
    </dependency>
    
  6. Instantiate REngine (I need this version in order to pass dataframe to R from java)

    String[] Args = {"--vanilla"};
    REngine engine = REngine.engineForClass("org.rosuda.REngine.JRI.JRIEngine", Args, new REngineStdOutput (), false);
    

What you should end up with looks something like this at runtime, if you instantiate with the callback argument (new REngineStdOutput () ); otherwise if you just instantiate with the String engineForClass("org.rosuda.REngine.JRI.JRIEngine"), you'll wont get the below output from R on startup/elsewise, depending on if you want it or not:

    /**R version 3.3.1 (2016-06-21) -- "Bug in Your Hair"
    Copyright (C) 2016 The R Foundation for Statistical Computing
    Platform: x86_64-apple-darwin15.5.0 (64-bit)

    R is free software and comes with ABSOLUTELY NO WARRANTY.
    You are welcome to redistribute it under certain conditions.
    Type 'license()' or 'licence()' for distribution details.

      Natural language support but running in an English locale

    R is a collaborative project with many contributors.
    Type 'contributors()' for more information and
    'citation()' on how to cite R or R packages in publications.

    Type 'demo()' for some demos, 'help()' for on-line help, or
    'help.start()' for an HTML browser interface to help.
    Type 'q()' to quit R.**/

Hope this helps someone in the future and saves them from the pain.

Upvotes: 4

Gergely Bacso
Gergely Bacso

Reputation: 14651

You need to build a jar with all your dependencies included. (aka fat jar) Since you are already using Maven, the only thing you need to do is to instruct Maven to include the dependencies by adding this plugin to your pom.xml file:

<build>
   <plugins>
      <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-assembly-plugin</artifactId>
            <version>2.5.5</version>
            <configuration>
                <descriptorRefs>
                    <descriptorRef>jar-with-dependencies</descriptorRef>
                </descriptorRefs>
            </configuration>
            <executions>
                <execution>
                    <id>assemble-all</id>
                    <phase>package</phase>
                    <goals>
                        <goal>single</goal>
                    </goals>
                </execution>
            </executions>
      </plugin>
   </plugins>
</build>

Upvotes: 1

Koby
Koby

Reputation: 615

You are missing the classpath argument. Your jar file contains your compiled code without any 3rd party jars. When you want to run it, you should add -cp and point to all your 3rd party jars.

You can also build a single jar with all dependencies using Maven's assembly plugin.

Upvotes: 0

Related Questions