【问题标题】:How to execute a class with main method which is present in fatJar created by gradle如何使用 gradle 创建的 fatJar 中存在的 main 方法执行类
【发布时间】:2018-01-10 07:19:12
【问题描述】:

这是how to execute a built fat JAR as a gradle task? 的后续问题 我没有足够的分数来提出我的问题作为评论。所以我不得不再问一次。这个问题已多次以其他形式和场景被问过,但这些回答都没有帮助我。

我的问题:

场景 1:使用 gradle fatJar 创建具有依赖关系的单个 jar

场景 2:使用 maven 程序集创建具有依赖关系的单个 jar

执行

java -cp sample.jar com.example.ClassA

关于两个进程中生成的 jar 文件。

问题: Process 1 中的 jar 给了我

错误:无法找到或加载主类 com.example.ClassA

进程 2 中的 jar 正确执行。

我已经提取了两个 jar 文件,它们都具有相同的文件夹结构和相同的文件 - 这意味着编译的类文件存在于两个 jar 文件中。

我没有在这两个进程中指定任何清单条目,因为我有多个主类并且我没有尝试生成可执行的 jar 文件。

我的 build.gradle 文件如下所示:

apply plugin: 'java'
apply plugin: 'maven'

sourceCompatibility = 1.8
targetCompatibility = 1.8

repositories {
    mavenLocal()
}

sourceSets {
    main{
      java{
         srcDirs 'src/main/java'
          }
      }
}

processResources {
    from 'src/main/resources'
}

task compile (type: JavaCompile) {
    source = sourceSets.main.java.srcDirs
    include '**/*.java'
    classpath = sourceSets.main.compileClasspath
    destinationDir = sourceSets.main.output.classesDir
}

compile.options.compilerArgs = ["-sourcepath", "$projectDir/src/main/java"]

dependencies {
    .
    .
    .

}

task fatJar(type:Jar) {
    baseName = 'xxxxxxx'
    from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } }
    with jar
}

defaultTasks 'clean', 'compile', 'fatJar'

编辑 - 1:

我尝试过 jar 的相对路径、jar 的绝对路径,甚至浏览到包含 jar 的文件夹。一点运气都没有。

我尝试使用 '/' 而不是 '.'在包名中。那里也没有运气。

我尝试过使用 java VM 参数来提供足够大的堆空间。纳达。

尝试在 powershell 上执行。出现以下错误:

+ CategoryInfo          : NotSpecified: (Error: Could not lo...ClassA:String) [], RemoteException

+ FullyQualifiedErrorId : NativeCommandError

我想直接看内容所以使用了 jar -tvf path_to_jar\sample.jar 。有趣的是 jar 命令没有执行并抱怨在类路径中找不到命令。我必须浏览到 java 安装目录并执行命令,它会显示文件内容。

我的想法和选项都用完了。 有什么指点吗?

【问题讨论】:

    标签: java maven gradle


    【解决方案1】:

    由于某种原因,无论我为 fatJar 使用哪种配置,最终的 jar 在尝试执行主类时都会出错。

    使用 ShadowJar 任务,我能够构建必要的 jar 并执行问题中指定的主类。

    我知道这违背了关于使用 fatJar 和执行主类的问题的全部目的。但由于时间限制,我不得不寻找替代方案。

    对于那些正在为 Shadow Jar 任务寻找配置的人,我使用以下方法:

    buildscript {
        repositories {  
            mavenLocal()    
            dependencies {
                classpath 'com.github.jengelman.gradle.plugins:shadow:1.2.3'
            }
        }
    }
    
    
    apply plugin: 'com.github.johnrengelman.shadow'
    

    最后为了执行任务,我使用了

    gradle shadowJar
    

    【讨论】:

      【解决方案2】:

      您的执行命令似乎无效。构建项目后:

      ./gradlew clean fatJar
      

      您应该使用以下命令来执行您的程序:

      java -cp build/libs/xxxxxxx.jar com.example.ClassA
      

      参数-cp build/libs/xxxxxxx.jar为即将启动的JVM设置类路径,它必须指向现有的JAR文件(你可以使用这个文件的相对或绝对路径)。

      看看我几分钟前录制的以下截屏视频:

      你可以看到,如果我将执行命令改为:

      java -cp xxxxxxx.jar com.example.ClassA
      

      我得到了和你一样的错误:

      Error: Could not find or load main class com.example.ClassA
      

      在这里你可以找到一个simple Gradle project 我曾经玩过你的build.gradle 文件示例。我添加了一个依赖项来证明 fatJar 构建了一个具有依赖项的 JAR,并且我添加了带有 public static void main(String[] args) 的类以证明您可以从命令行选择任何主类。希望对你有帮助。

      【讨论】:

      • @2194470 我发现您所做的与我的方案之间存在一些差异。 1. 我在 Windows 上进行测试,您可能在 Mac 上进行了测试。我不认为这与这个问题有任何关系。 2. 我正在使用简单的“gradle”命令执行 fatJar,而您使用了“graddew”包装命令。我会试试这个,让你知道。顺便说一句,执行 fatJar 时使用 gradle 和 gradlew 有什么区别吗?
      • 我几乎可以肯定您的问题是由您在java -cp ... 命令中传递的 JAR 文件的错误路径引起的。首先尝试将绝对路径传递给该文件。 Windows/Linux 的差异在这里应该不是问题,因为这个错误是由 JVM 抛出的。使用gradlew 与本地安装的gradle 相比没有区别——我使用它主要是因为它更容易与其他相同版本的gradle 共享。
      • 用额外的 cmets 编辑了问题,你能再检查一次吗?
      猜你喜欢
      • 2020-05-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-20
      • 1970-01-01
      • 2015-11-03
      相关资源
      最近更新 更多