测试中的NoSuchMethodError使用gradle运行

时间:2015-10-20 18:30:20

标签: gradle

我正在尝试将MAVEN Java项目实验性地移植到gradle。我遇到的一个问题是由于NoSuchMethodError在运行时(执行期间)发生而无法执行单元测试。我正在调用FileUtils.write()方法。

我修改了我的代码以跟踪加载了FileUtils类的ClassLoader中可用的类路径,我有以下内容:

C:/Sdk/gradle-2-7/lib/commons-io-1.4.jar
C:/Users/<me>/.gradle/caches/modules-2/files-2.1/commons-io/commons-io/2.4/b1b6ea3b7e4aa4f492509a4952029cd8e48019ad/commons-io-2.4.jar

除此之外,我看到在测试运行期间类路径中有2个版本的commons-io,而第一个带有gradle的版本因此具有更高的优先级。

根本原因是什么?如何解决这个问题?

实际上,我希望除了在我的gradle项目的依赖项中显式声明之外,在类路径中没有可用的JAR。

更新:似乎我已经了解了根本原因 - 正在测试的项目是'gradle plugin'并且在gradle中编译它我必须在{{1 }}:

build.gradle

这会将所有gradle依赖项捕获到我的项目中。虽然我仍然没有找到修复它的方法:

  • 我无法删除它,因为项目不会编译
  • 我无法排除某些内容,因为gradle不支持此dependencies { compile gradleApi() } (请参阅http://gradle.1045684.n5.nabble.com/exclude-some-dependencies-from-gradleApi-dependency-td5712103.html)。
  • 我不能只添加那些我真正需要的gradle jar作为依赖项 - 我没有看到任何方法在编译依赖项中显式引用它们,我没有看到任何包含这些工件的公共存储库。注意:对于MAVEN构建,我已手动将它们上传到本地MAVEN仓库。

2 个答案:

答案 0 :(得分:0)

TL; DR

不要使用commons-io:2.1,使用Java8,Groovy,或者使用helper来代替commons-io。

<强> Explination

根本原因是gradleApi()包含commons-io:1.4并且当测试执行时,你最终在类路径上有两个commons-io jar并且1.4版本恰好更早,以便&#39;为什么你得到NoSuchMethodError

这是因为Gradle没有像Maven那样在单独的类加载器中隔离每个插件。鉴于Gradle的工作原理,您无法做到。这是因为在Gradle中,一个好的设计策略是将多个插件链接在一起做一件事。您有一个插件可以将事物配置为通用的,并且没有关于如何使用它的意见。然后你有一个非常固执的插件,用一些假设来配置一个项目。当用户没有与您分享相同的意见时,这很有用,他们可以只应用基本插件并应用他们自己的意见。

更具体的例子是你有一个包含其他插件使用的extension的jar。这可能是&#34; failBuildOnQualityError&#34;。然后,当checkstyle,findbugs,jacoco等发现问题时,每个单独的插件(使用不同的坐标)将尝试使用该扩展来查看它们是否应该使构建失败。

答案 1 :(得分:0)

好的,我最初的诊断“ Gradle没有将插件的类路径与自己的类路径隔离”是错误的。根本原因实际上是......

dependencies {
    compile gradleApi()
}

...摄取到许多依赖项(包括commons-io:1.4)。正确的解决方案(至少对我来说可行)只包括明确要求的罐子:

versions = [
    gradle: "2.8",
    groovy: "2.4.4",
]

dependencies {
    compile "org.codehaus.groovy:groovy-all:${versions.groovy}"
    compile "org.gradle:gradle-base-services:${versions.gradle}"
    compile "org.gradle:gradle-base-services-groovy:${versions.gradle}"
    compile "org.gradle:gradle-core:${versions.gradle}"
    compile files("lib/gradle-platform-jvm-${versions.gradle}.jar")
}

注意:

  • gradle的核心依赖项应该通过公共工件ID引用(而不是通过直接JAR文件引用)。这种方式在运行时gradle使用关联的POM来构建传递的运行时依赖项。否则,在执行单元测试期间,您将获得NoClassDefFoundError,因为其他gradle的内部不在执行类路径中。

  • 看起来并非所有gradle的工件都可以在公共存储库(jcenter)中使用。如果你的插件中你要构建对其他“本机”任务的依赖(比如'jar') - 它们的实现必须直接通过JAR文件引用。

相关问题