get“找不到或加载主类”

mnowg1ta  于 2021-07-13  发布在  Spark
关注(0)|答案(2)|浏览(316)

我正在尝试创建一个可执行的.jar,其中包含一些提供的依赖项,我有一个从'gradle init'创建的简单示例,在添加几个提供的依赖项之前,我可以执行.jar,但是添加这些依赖项之后它就失败了。
我可以复制如下:

mkdir /tmp/foo
cd /tmp/foo
run 'gradle init'

Select type of project to generate:
      2: application

Select implementation language:
      3: Java

Select build script DSL:
  1: Groovy

Select test framework:
  1: JUnit 4

Project name (default: foo):
Source package (default: foo):

然后在build.gradle的末尾添加以下内容:

jar {
    manifest {
        attributes "Main-Class": "foo.App"
    }
    zip64 = true
    from {
        configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }
    }
}

在命令行中,运行:

gradle clean ; gradle jar ; java -jar  build/libs/foo.jar

你应该看到:

Hello world.

现在将build.gradle中的“dependencies”块更改为:

configurations {
        provided
        compile.extendsFrom(provided)
}

dependencies {
    implementation 'com.google.guava:guava:29.0-jre'
    testImplementation 'junit:junit:4.13'
    implementation "org.apache.spark:spark-sql_2.11:2.4.4"
    implementation "org.apache.spark:spark-hive_2.11:2.4.4"
}

在命令行中,再次运行:

gradle clean ; gradle jar ; java -jar  build/libs/foo.jar

你应该看到一切都是好的:

Hello world.

下一步,请更换

implementation "org.apache.spark:spark-sql_2.11:2.4.4"
    implementation "org.apache.spark:spark-hive_2.11:2.4.4"

具有

provided "org.apache.spark:spark-sql_2.11:2.4.4"
    provided "org.apache.spark:spark-hive_2.11:2.4.4"

在命令行中,再次运行:

gradle clean ; gradle jar ; java -jar  build/libs/foo.jar

这次您将获得:

Error: Could not find or load main class foo.App

因此,这显然是由于试图使spark相关的依赖项“被提供”,因此不是.jar的一部分。但是,您会注意到foo.app类非常简单,与spark无关。所以,我现在很困惑,为什么在添加这些类型的依赖项时主类突然变得不可用。提前感谢您的帮助!

iovurdzv

iovurdzv1#

您可能自己也注意到了(这可能也是您想要的):构建的jar文件包含您使用时所有依赖jar的全部内容 provided (或 compile )而不是 implementationdependencies 阻止。
问题是你的 jar 任务配置实际上包含了依赖jar的所有内容,包括它们的 META-INF/ 目录文件。这些依赖jar中的一些似乎是经过签名的,因此在其内部包含数字签名 META-INF/ 目录–由您的 jar 任务也是。运行时 java -jar … ,这些签名会妨碍并导致类未找到错误(即使类在jar中)。
一个简单的解决方法是在创建jar文件时排除签名:

jar {
    exclude 'META-INF/*.DSA'
}

学分归这个所以回答。

tktrz96b

tktrz96b2#

下面是一个结合了chriki的解决方案和shadowjar方法的答案,shadowjar方法也对我有效。你挑吧!如果这篇文章对你有帮助,请投票给克里基。

plugins {
    // Apply the java plugin to add support for Java
    id 'java'

    // Apply the application plugin to add support for building a CLI application.
    id 'application'

    // This was what I used in my solution
    id 'com.github.johnrengelman.shadow' version '5.2.0'
}

repositories {
    // Use jcenter for resolving dependencies.
    // You can declare any Maven/Ivy/file repository here.
    jcenter()
}

configurations {
        provided
        compile.extendsFrom(provided)
}

dependencies {
    implementation 'com.google.guava:guava:29.0-jre'
    testImplementation 'junit:junit:4.13'
    provided "org.apache.spark:spark-sql_2.11:2.4.4"
    provided "org.apache.spark:spark-hive_2.11:2.4.4"
}

application {
    // Define the main class for the application.
    mainClassName = 'foo.App'
}

test {
    // Use junit platform for unit tests
    useJUnitPlatform()
}

jar {
    // Line below does the trick if you are using 'gradlew jar' 
    // Shout out / big ups to: Chriki
    // Note: My solution (using shadow gradle plugin) 
    // does not require this, but it doesn't hurt
    exclude 'META-INF/*.DSA'            
    manifest {
        attributes "Main-Class": "foo.App"
    }
    zip64 = true
    from {
        configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }
    }
}

// This was the second part of what I used in my solution 
// When building, specify: 'gradlew shadowJar' - the jar you want has -all* in it.
// Run with: java -jar  build/libs/foo-all.jar
shadowJar {
    zip64 = true        // I had to specify this twice.. OK.. not gonna lose sleep.
}

相关问题