【问题标题】:Running a Gradle compiled Java application with dependencies via the java command通过 java 命令运行带有依赖项的 Gradle 编译的 Java 应用程序
【发布时间】:2015-06-05 10:44:21
【问题描述】:

我正在尝试使用 Gradlethis article explaining the Swing Application Framework (JSR 296) 编译代码示例 3,并使用 java 命令从命令行运行它。

我的目录布局如下:

├── build.gradle
└── src/
    └── main/
        └── java/
            └── demo/
                └── BasicSingleFrameApp.java

build.gradle 文件定义了对appframework 的依赖:

apply plugin: 'java'

repositories {
  mavenCentral()
}

dependencies {
  compile 'org.jdesktop:appframework:1.0.3'
}

这是BasicSingleFrameApp.java 文件,是上述文章示例的副本,通过包声明进行了增强:

package demo;

import org.jdesktop.application.*;
import javax.swing.*;
import java.awt.*;

public class BasicSingleFrameApp extends SingleFrameApplication {
    JLabel label;

    @Override
    protected void startup() {
        getMainFrame().setTitle("BasicSingleFrameApp");
        label = new JLabel("Hello, world!");
        label.setFont(new Font("SansSerif", Font.PLAIN, 22));
        show(label);
    }

    public static void main(String[] args) {
        Application.launch(BasicSingleFrameApp.class, args);
    }

}

使用gradle build 编译工作正常且没有错误。

但是当我尝试运行 BasicSingleFrameApp

$ java -cp build/classes/main/ demo.BasicSingleFrameApp

我收到错误消息:

Error: Could not find or load main class demo.BasicSingleFrameApp

当我用简单的“Hello, world!”替换 BasicSingleFrameApp 类时没有依赖的打印类,一切正常。

我很困惑,因为根据我的理解,我正确设置了类路径,但我不明白为什么找不到 main 方法(具有正确的签名)。

这是我的 Java 版本:

java version "1.8.0_20"
Java(TM) SE Runtime Environment (build 1.8.0_20-b26)
Java HotSpot(TM) 64-Bit Server VM (build 25.20-b23, mixed mode)

我正在运行 Mac OS X Yosemite 10.10.2。

【问题讨论】:

  • 你确定桌面 jsr jar 在类路径上吗?
  • 你能说得更具体一点吗? Gradle 报告(通过gradle dependencies)“编译源集'main'的类路径”包含org.jdesktop:appframework:1.0.3org.jdesktop:swing-worker:1.1。 “源集'main'的运行时类路径”也是如此。
  • (几乎)和我一样的问题。 Gradle 的复杂程度让我大吃一惊……

标签: java gradle dependencies


【解决方案1】:

好的,所以@chuchikaeschtli 帮助我找到了问题的核心,即 Gradle 管理用于编译的依赖项并报告在运行时执行此操作,但需要更多手动任务才能使这些依赖项在运行时可用。

我仍然感到困惑的是我收到的不直观的错误消息:

Error: Could not find or load main class demo.BasicSingleFrameApp

我本以为会出现与运行时缺少依赖项有关的问题,以报告类似的错误

error: package org.jdesktop.application does not exist

这是我在编译时缺少这些依赖项时遇到的错误。

Gradle 给了我以下关于运行时依赖项的报告(通过运行 gradle dependencies),我认为 Gradle 以某种方式管理这些:

compile - Compile classpath for source set 'main'.
\--- org.jdesktop:appframework:1.0.3
     \--- org.jdesktop:swing-worker:1.1
…
runtime - Runtime classpath for source set 'main'.
\--- org.jdesktop:appframework:1.0.3
     \--- org.jdesktop:swing-worker:1.1
…

最后,在知道是缺少运行时依赖的问题后,我找到了几种提供它们的方法,我将分享。

第一个解决方案:链接到缓存

正如this Stackoverflow answer 中所述,Gradle 将依赖项缓存在$HOME/.gradle 中,但它们的实际路径很棘手。答案描述了一个小的 Gradle 任务,它输出缓存中每个依赖项的完整路径(在此示例中为 compile 配置,这是我所需要的):

task showMeCache << {
  configurations.compile.each { println it }
}

就我而言,gradle showMeCache 报告:

$HOME/.gradle/caches/modules-2/files-2.1/org.jdesktop/appframework/1.0.3/338045feff6e61df237aafd11b6f3fe1a3b4e60e/appframework-1.0.3.jar
$HOME/.gradle/caches/modules-2/files-2.1/org.jdesktop/swing-worker/1.1/dc9f8d6f7236087924aad28fbec794a087dd1b3d/swing-worker-1.1.jar

这些是又长又讨厌的文件路径,但我可以构造一个java 命令,该命令以@chuchikaeschtli 建议的样式工作:

java \
-cp build/classes/main/\
:$HOME/.gradle/caches/modules-2/files-2.1/org.jdesktop/appframework/1.0.3/338045feff6e61df237aafd11b6f3fe1a3b4e60e/appframework-1.0.3.jar\
:$HOME/.gradle/caches/modules-2/files-2.1/org.jdesktop/swing-worker/1.1/dc9f8d6f7236087924aad28fbec794a087dd1b3d/swing-worker-1.1.jar \
demo.BasicSingleFrameApp

这行得通,但当然感觉不是很“正确”。但这有助于理解问题:这实际上是缺少依赖 jar 的问题。

第二种解决方案:将依赖项同步到build 目录

Using the Sync task of the Gradle User Guide 部分中,它明确使用了一个示例来描述手头问题的更好解决方案:

这是一个在 build/libs 目录中维护项目运行时依赖项副本的示例。

task libs(type: Sync) {
  from configurations.runtime
  into "$buildDir/libs"
}

使用gradle libs 运行此任务后,我能够构建一个更简单的工作java 命令:

java -cp build/classes/main/:build/libs/appframework-1.0.3.jar:build/libs/swing-worker-1.1.jar demo.BasicSingleFrameApp

记住:这些依赖项默认没有同步到build目录!

第三种解决方案:使用 Gradle 运行应用程序

Application Plugin Gradle 本身为运行应用程序提供了便捷的解决方案。将这两行添加到我的build.gradle

apply plugin:'application'

mainClassName = 'demo.BasicSingleFrameApp'

我只用gradle run 就能成功启动应用程序。迄今为止最简单的解决方案!

请注意,应用程序插件还提供了一个名为 installDist 的任务,该任务在 build/install 内创建了应用程序及其所有依赖项的可运行分发,并带有用于 UNIX 和 Windows 系统的启动脚本。这样做的好处是不需要 Gradle 来执行应用程序。

另外,如果您喜欢应用程序插件的gradle run 任务,但担心Gradle 在目标系统上是否可用,请查看Gradle Wrapper

第四个解决方案:创建One-JAR、Fat Jar 或 Uber Jar

似乎存在 Gradle-only waysGradle plugins 来帮助创建这些包含应用程序所需的所有依赖项的 jar。

对于gradle-one-jar-Plugin,应用程序可以使用java 命令启动,例如:

java -jar build/libs/YOUR_APP_NAME-standalone.jar

【讨论】:

    【解决方案2】:

    据我所知,您正在使用 java 启动应用程序,因此您必须告诉 java 在哪里可以找到您下载的 swing 应用程序框架 jar。所以命令应该看起来像

    java -cp pathtojdektopjar/jdesktopjar.jar;build/classes/main/ demo.BasicSingleFrameApp
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-07-04
      • 2017-05-28
      • 2020-05-04
      • 1970-01-01
      • 2018-06-13
      • 1970-01-01
      • 1970-01-01
      • 2014-04-05
      相关资源
      最近更新 更多