为什么我的 Spock 单元测试在升级到 JDK 8 后在 Gradle 构建中失败?

Why my Spock unit tests fail in Gradle build after upgrading to JDK 8?

我正在尝试使用 JDK 8、Groovy 2.4.4、Spock 1.0-groovy-2.4、Gradle 1.11 编译我的应用程序源代码(我的公司在此基础上构建了自定义插件)

gradle -version
Groovy:       1.8.6
Ant:          Apache Ant(TM) version 1.9.2 compiled on July 8 2013
Ivy:          2.2.0
JVM:          1.7.0_51 (Oracle Corporation 24.51-b03)
OS:           Windows 7 6.1 amd64

在我的构建环境中,我需要为其他项目保留我的 JAVA_HOME 到 Java 7。

JAVA_HOME = C:\Program Files\Java\jdk1.7.0_51
JAVA8_HOME = C:\Program Files\Java\jdk1.8.0_60

因此,在我的 build.gradle 中,我明确告诉 Gradle 使用 JDK 8

tasks.withType(JavaCompile) {
    options.fork = true;
    options.forkOptions.executable = "${System.env.JAVA8_HOME}/bin/javac"
}

tasks.withType(Test) {
    executable = "${System.env.JAVA8_HOME}/bin/java"
}

compileJava{
    sourceCompatibility = 1.8
    targetCompatibility = 1.8
}

源文件编译成功,但是当它到达单元测试时(用 Spock 编写),它失败并出现以下错误。

Caused by: java.lang.UnsupportedClassVersionError: org/model/SDA : Unsupported major.minor version 52.0

我确认 SDA.class 是使用 JDK 8.

编译的
javap -verbose SDA.class | findstr "major"
  major version: 52

为什么只有在单元测试期间我才会收到上述错误?这是否意味着 运行 在 JDK 7 上进行单元测试?

将此添加到您的 gradle.properties:

org.gradle.java.home=/path/to/java8

或者当你启动gradle时,你可以将它指定为jvm参数:

gradle -Dorg.gradle.java.home=/path/to/java8 task1 task2

因此,如果您真的热衷于黑客攻击,那么您可以做些事情。它确实涉及覆盖某些 Gradle 内部构件 - 因此它可能不适用于 1.11 以外的任何 Gradle 版本。也可能会有意想不到的副作用。

import org.gradle.internal.Factory
import org.gradle.process.internal.WorkerProcessBuilder
import org.gradle.api.internal.tasks.compile.daemon.CompilerDaemonStarter

tasks.withType(GroovyCompile) {
    options.fork = true
    options.forkOptions.executable = "${System.env.JAVA8_HOME}/bin/javac"

    doFirst {
        def compilerFactory = compiler.compiler.compilerFactory
        def clientsManager = compilerFactory.compilerDaemonManager.clientsManager
        def oldDaemonStarter = clientsManager.compilerDaemonStarter
        if (!(oldDaemonStarter.workerFactory instanceof CustomWorkerProcessFactory)) {
            println "HACK, installing custom daemon worker"
            clientsManager.compilerDaemonStarter = new CompilerDaemonStarter(
                    new CustomWorkerProcessFactory(oldDaemonStarter.workerFactory),
                    oldDaemonStarter.startParameter)
        }
    }
}

class CustomWorkerProcessFactory implements Factory<WorkerProcessBuilder> {
    Factory<WorkerProcessBuilder> delegate

    CustomWorkerProcessFactory(Factory<WorkerProcessBuilder> delegate) {
        this.delegate = delegate
    }

    public WorkerProcessBuilder create() {
        def newWorker = delegate.create()
        newWorker.javaCommand.executable("${System.env.JAVA8_HOME}/bin/java")
        newWorker
    }
}