我正在尝试构建一个可以调用R代码的JAR库。 我基本上希望这个jar能够在任何支持运行jar可执行文件的机器上运行(不需要单独的R软件)。 为此,我使用Maven。我能够编译并创建一个没有任何错误的jar。但是,当我运行它时,我无法获得成功的结果。
这是我的java代码
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.");
}
}
这是我的pom.xml文件
<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>
我使用mvn clean
然后使用mvn package
来创建jar文件。
在C:\MVN\project\analytics\timeseries\target
中创建了一个4KB的JAR文件。从Windows上的命令行来看,当我运行执行这个jar文件时,我收到以下错误
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
我想知道我犯的是什么错误。我试图通过谷歌搜索找到答案,但我无法修复它。
答案 0 :(得分:4)
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):
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)"
Install R using brew:
brew tap homebrew/science
brew install R
Install rJava with R (takes a bit of compile time, grab a coffee)
install.packages("rJava")
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
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>
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.
答案 1 :(得分:1)
您需要构建一个包含所有依赖项的jar。 (又名fat jar)由于你已经在使用Maven,你唯一需要做的就是通过将这个插件添加到你的pom.xml文件来指示Maven包含依赖项:
<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>
答案 2 :(得分:0)
您缺少classpath参数。您的jar文件包含您编译的代码,没有任何第三方jar。当你想运行它时,你应该添加-cp并指向你所有的第三方罐子。
您还可以使用Maven的assembly插件构建一个包含所有依赖项的jar。