使用gradle进行测试运行时出现NoSuchMethodError
我正在尝试将一个MAVEN java项目移植到gradle。我遇到的一个问题是无法执行单元测试,因为在运行时(执行期间)没有发生任何方法错误。我正在调用使用gradle进行测试运行时出现NoSuchMethodError,gradle,Gradle,我正在尝试将一个MAVEN java项目移植到gradle。我遇到的一个问题是无法执行单元测试,因为在运行时(执行期间)没有发生任何方法错误。我正在调用FileUtils.write()方法 我修改了代码,以跟踪加载FileUtils类的类加载器中可用的类路径,并得到以下结果: C:/Sdk/gradle-2-7/lib/commons-io-1.4.jar C:/Users/<me>/.gradle/caches/modules-2/files-2.1/commons-io/com
FileUtils.write()
方法
我修改了代码,以跟踪加载FileUtils类的类加载器中可用的类路径,并得到以下结果:
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
这会将所有gradle依赖项都渗透到我的项目中。尽管我仍然没有找到解决方法:
- 我无法删除它,因为项目无法编译
- 我不能排除某些内容,因为gradle不支持
(请参阅)gradleApi()
- 我不能只添加我真正需要的gradle jar作为依赖项—我看不到任何在编译依赖项中显式引用它们的方法,我看不到任何包含这些工件的公共存储库。注意:对于MAVEN build,我已经手动将它们上传到本地MAVEN repo
- TL;DR
不要使用commons io:2.1,或者使用Java8、Groovy,或者使用一个助手来代替commons io
解释
根本原因是
gradleApi()
包含commons io:1.4,当测试执行时,类路径上有两个commons io jar,而1.4版本恰好更早,因此您会得到NoSuchMethodError
这是因为Gradle不像Maven那样将每个插件隔离在单独的类加载器中。考虑到格拉德尔的工作方式,你不能。这是因为在Gradle中,一个好的设计策略是让多个插件链接在一起做一件事。你有一个插件,它将事物配置为通用的,并且没有关于如何使用它的意见。然后你有一个非常固执己见的插件,它用很多假设来配置一个项目。当用户与您的意见不一致时,这很有用,他们可以应用基本插件并应用自己的意见
一个更具体的例子是,您有一个jar,其中包含其他插件使用的。这可能类似于“failBuildOnQualityError”。然后,当checkstyle、findbugs、jacoco等发现问题时,每个单独的插件(使用不同的坐标)都会尝试使用该扩展来查看它们是否会导致构建失败。好的,我最初关于“Gradle不会将插件的类路径与自己的类路径隔离”的诊断是错误的。根本原因实际上是
dependencies {
compile gradleApi()
}
。。。摄取到许多依赖项(包括commons io:1.4)。正确的解决方案(至少对我来说是可行的)是只明确包含所需的JAR:
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文件直接引用它们的实现
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")
}