【问题标题】:Running jar built using Maven causes "java.lang.NoClassDefFoundError: org/rosuda/JRI/Rengine" error运行使用 Maven 构建的 jar 会导致“java.lang.NoClassDefFoundError: org/rosuda/JRI/Rengine”错误
【发布时间】:2015-08-23 19:29:13
【问题描述】:

我正在尝试构建一个可以调用 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 cleanmvn 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

我想弄清楚我犯了什么错误。我试图通过谷歌搜索找到答案,但无法解决。

【问题讨论】:

    标签: java r eclipse maven jar


    【解决方案1】:

    因为我已经为此苦恼了一天,我可能会在未来忘记并参考此页面 - 根据 Gergely Basco 在上述评论中的建议,严格来说,R 和 rJava 都需要安装在机器上以便在实例化 org.rosuda.REngine.REngine 对象时解决 Cannot find JRI native library! 问题,而这不能仅通过在 pom.xml 中添加 JRIEngine 依赖项来完成(糟糕)。

    步骤(对于我以后的图像我是如何做的):

    1. 安装 Brew(我只是碰巧将 Brew 用于其他依赖项)

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

      brew tap homebrew/science
      brew install R
      
    3. 用 R 安装 rJava(需要一点编译时间,喝杯咖啡)

      install.packages("rJava")
      
    4. 将 rJava/jri 添加到 java.library.path 类路径,将 R_HOME 添加到环境变量(您安装 R 的位置 - 在我的情况下,Brew 安装它的位置)。请注意,如果您尝试在 IDE 中运行它(我正在运行 IDEA16),它不会继承您在 ~/.bash_profile 中设置的路径,您需要在运行配置中进行设置。

       -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. 确保maven在pom.xml中有对JRIEngine的依赖

      <dependency>
          <groupId>com.github.lucarosellini.rJava</groupId>
          <artifactId>JRIEngine</artifactId>
          <version>0.9-7</version>
      </dependency>
      
    6. 实例化 REngine(我需要这个版本才能将数据帧从 java 传递给 R)

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

    如果您使用回调参数 (new REngineStdOutput ()) 进行实例化,那么在运行时您应该得到的结果看起来像这样;否则,如果您只是使用字符串 engineForClass("org.rosuda.REngine.JRI.JRIEngine") 进行实例化,您将不会在启动/否则时从 R 获得以下输出,具体取决于您是否需要:

        /**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.**/
    

    希望这对未来的人有所帮助,并使他们免于痛苦。

    【讨论】:

      【解决方案2】:

      您需要构建一个包含所有依赖项的 jar。 (aka 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>
      

      【讨论】:

      • 我现在收到此错误。 Creating Rengine (with arguments) Cannot find JRI native library! Please make sure that the JRI native library is in a directory listed in java.library.path. java.lang.UnsatisfiedLinkError: no jri in java.library.path at java.lang.ClassLoader.loadLibrary(Unknown Source) at java.lang.Runtime.loadLibrary0(Unknown Source) at java.lang.System.loadLibrary(Unknown Source) at org.rosuda.JRI.Rengine.&lt;clinit&gt;(Rengine.java:19) at com.company.analytics.timeseries.App.main(App.java:10) maven 不应该解决这个依赖关系吗?
      • 这比这要复杂一些。您在类路径上有 R 主目录吗? %R_HOME%\bin;%R_HOME%\bin\i386;%R_HOME%\library\rJava\jri\i386?
      • 不,我没有。我既没有配置 R_HOME 也没有配置 CLASSPATH。
      • 我希望这个 jar 包含所有 R 依赖项,以便它可以在 R 软件不可用的任何服务器上运行。即,只有唯一的依赖项是 jar 和 jvm。我的期望合理吗?我相信设置 R_HOME 意味着然后单独安装 R 软件,而不是作为 JAR。然后它不会满足我的目的,因为我想使用这个 jar 的服务器上可能没有安装 R。我对 R_HOME 的理解可能是错误的。如果是,请纠正我。
      • 解决原来的 NoClassDefFoundError 是一件简单的事情,因为那是关于直接依赖的。缺少的 REngine 库仍在 Java 领域内,因此在那里构建一个胖 jar 是一种选择。您现在面临的错误是在机器上拥有 R 环境本身,并且无法通过构建特殊的 jar 文件来解决。
      【解决方案3】:

      您缺少类路径参数。您的 jar 文件包含您编译的代码,没有任何 3rd 方 jar。当你想运行它时,你应该添加 -cp 并指向你所有的 3rd 方 jars。

      您还可以使用 Maven 的 assembly 插件构建一个包含所有依赖项的单个 jar。

      【讨论】:

      • 我尝试按照 Gerely Basco 的建议创建一个带有依赖项的 jar。我相信这就是你所建议的。我现在收到“找不到 JRI 本机库!”的问题。我实际上期待 Maven 找到那个库,但不幸的是它没有。
      猜你喜欢
      • 1970-01-01
      • 2018-06-30
      • 1970-01-01
      • 1970-01-01
      • 2018-05-02
      • 1970-01-01
      • 2011-01-02
      • 1970-01-01
      相关资源
      最近更新 更多