当前位置: 首页 > 知识库问答 >
问题:

如何使用Gradle 4.4创建一个包含所有依赖项的jar?

宋朝
2023-03-14

这个问题与这个问题有关-但是,由于弃用编译而支持实现,它不起作用。它确实拾取了用编译声明的依赖项。然而,由于它被弃用,使用它不是一个选项(无论如何,当它被删除时,我们会回到这里)

我有一个Gradle任务:

task fatJar(type: Jar) {
    manifest {
        attributes 'Implementation-Title': 'rpi-sense-hat-lib',
                'Implementation-Version': version,
                'Main-Class': 'io.github.lunarwatcher.pi.sensehat.Tests'
    }
    baseName = project.name
    from { 
        configurations.compile.collect {
            it.isDirectory() ? it : zipTree(it)
        }
    }
    with jar
}

除了测试依赖之外,还有一个依赖项:

dependencies {
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
    testImplementation group: 'junit', name: 'junit', version: '4.12'
}

从IDE运行很好。然而,当我部署到Raspberry Pi(或在本地使用jargradlew fatJar结果)时,我会遇到以下异常:

$ java -jar java-sense-hat-1.0a.jar
Exception in thread "main" java.lang.NoClassDefFoundError: kotlin/jvm/internal/Intrinsics
    at io.github.lunarwatcher.pi.sensehat.UtilsKt.getSenseHat(Utils.kt:18)
    at io.github.lunarwatcher.pi.sensehat.SenseHat.<init>(SenseHat.java:12)
    at io.github.lunarwatcher.pi.sensehat.Tests.main(Tests.java:9)
Caused by: java.lang.ClassNotFoundException: kotlin.jvm.internal.Intrinsics
    at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(Unknown Source)
    at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(Unknown Source)
    at java.base/java.lang.ClassLoader.loadClass(Unknown Source)
    ... 3 more

由以下行触发:

return Optional.empty()

在静态编程语言方法中,返回可选

kotlin运行时必须位于类路径中,并使用$echo$classpath进行验证。

或者你必须向maven添加kotlin-runtime,然后在jar内部使用mvn编译程序集进行组装:单个,

这意味着kotlin运行时不包括在类路径中。在回答“将kotlin运行时添加到依赖项”之前,它是stdlib的一部分:

Kotlin运行时(已弃用,请改用Kotlin stdlib工件)

我使用kotlin-stdlib-jdk8,它在IDE中工作。只是出于测试目的,使用kotlin-stdlib而不是改变任何东西。

此外,用compile替换implementation可以解决这个问题。

在我在问题顶部链接的帖子中,有人建议在fatJar任务中使用runtime。所以:

task fatJar(type: Jar) {
    manifest {
        attributes 'Implementation-Title': 'rpi-sense-hat-lib',
                'Implementation-Version': version,
                'Main-Class': 'io.github.lunarwatcher.pi.sensehat.Tests'
    }
    baseName = project.name
    from {
        configurations.compile.collect {
            it.isDirectory() ? it : zipTree(it)
        }
        configurations.runtime.collect {
            it.isDirectory() ? it : zipTree(it)
        }
    }
    with jar
}

依赖性仍然不包括在内,程序崩溃。

那么,为什么不将实现添加为要从中复制的配置呢?

我试过了。我的结局是:

task fatJar(type: Jar) {
    manifest {
        attributes 'Implementation-Title': 'rpi-sense-hat-lib',
                'Implementation-Version': version,
                'Main-Class': 'io.github.lunarwatcher.pi.sensehat.Tests'
    }
    baseName = project.name
    from {
        configurations.compile.collect {
            it.isDirectory() ? it : zipTree(it)
        }
        configurations.runtime.collect {
            it.isDirectory() ? it : zipTree(it)
        }
        configurations.implementation.collect {
            it.isDirectory() ? it : zipTree(it)
        }
    }
    with jar
}

还有一个例外:

不允许直接解析配置“实现”

因此,考虑到:

  • 编译而不是实现工作
  • 运行时异常来自Kotlin不在类路径中
  • 它在IDE中工作
  • implementation子句添加到fatJar任务会导致编译崩溃,但会出现一个单独的异常

当使用实现关键字时,如何在Gradle 4.4中生成包含所有依赖项的jar?


共有1个答案

姬捷
2023-03-14

你试过阴影插件像:

shadowJar {
  manifest {
     attributes 'Implementation-Title': 'rpi-sense-hat-lib',
            'Implementation-Version': version,
            'Main-Class': 'io.github.lunarwatcher.pi.sensehat.Tests'
  }
  configurations = [project.configurations.compile, project.configurations.runtime]
}

编辑:

您也可以这样做(如本问题的答案所述):

configurations {
    fatJar
}

dependencies {
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
    testImplementation group: 'junit', name: 'junit', version: '4.12'

    fatJar "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
}

task fatJar(type: Jar) {
    manifest {
        attributes 'Implementation-Title': 'rpi-sense-hat-lib',
                'Implementation-Version': version,
                'Main-Class': 'io.github.lunarwatcher.pi.sensehat.Tests'
    }
    baseName = project.name
    from {
        configurations.fatJar.collect {
            it.isDirectory() ? it : zipTree(it)
        }
    }
    with jar
}

但是,您必须将所有实现依赖项重复为法特加依赖项。对于您当前的项目,这很好,因为您只有一个依赖项,但是对于任何更大的项目,它会变得一团糟...

编辑2:

正如@Zoe在评论中指出的,这也是一个可以接受的解决方案:

task fatJar(type: Jar) {
    manifest {
        attributes 'Implementation-Title': 'rpi-sense-hat-lib',
                   'Implementation-Version': version,
                   'Main-Class': 'io.github.lunarwatcher.pi.sensehat.Tests'
    }
    baseName = project.name
    from {
        configurations.runtimeClasspath.collect {
            it.isDirectory() ? it : zipTree(it)
        }
    }
    with jar
}

但是请注意,根据源代码,runtimeClasspathruntimeOnlyruntime实现的组合,这可能是可取的,也可能不是,这取决于具体情况——例如,您可能不希望包含运行时依赖项,因为它们是由容器提供的。

 类似资料:
  • 好的,这是我第一次尝试Java web start,所以我有了用Maven构建的jar作为依赖项存储库,并将其放入Apache根文件夹,包括文件夹库中的所有依赖项jar,然后我创建了密钥存储、HTML和JNLP文件。 我启动了Apache服务,并尝试访问localhost,它运行得很顺利,直到我用浏览器的java插件运行了jnlp文件,显示,我知道我的依赖项JAR不包括在内。所以我发现了如何在Ja

  • 你能帮我解决这个问题吗? 谢了!

  • 我正在尝试创建一个jar文件,其中包含所有的依赖jar文件。Maven创建了一个单独的lib文件夹,并将所有的jar复制到其中,然后可执行jar就会工作,因为jar和lib位于同一位置,但我希望jar是主jar的一部分,而不是在lib文件夹中。我该怎么做?

  • 目前,要为Pax考试设置配置,我发现需要包含所有依赖项。比如说 但是由于依赖于,这感觉像是重复的信息。Pax Exam是否可能在不明确添加的情况下发现需要?

  • 我在{project_home}/src/test/groovy/中有一些功能测试 我希望能够使用一个gradle任务: 但是编译失败: 我确实在/build/libs下面有jar文件

  • 我需要创建所有依赖项的jar。我有一个spring项目,它与数据库一起工作,我需要在另一台计算机上启动Spring Boot应用程序,那里只有Java。我想只有一个jar文件,并用启动它,如何创建这个jar? UPD:我现在的pom: