diff --git a/buildSrc/src/main/groovy/org/apache/beam/gradle/BeamModulePlugin.groovy b/buildSrc/src/main/groovy/org/apache/beam/gradle/BeamModulePlugin.groovy index 650cdd944d37..1ed3b9d9b776 100644 --- a/buildSrc/src/main/groovy/org/apache/beam/gradle/BeamModulePlugin.groovy +++ b/buildSrc/src/main/groovy/org/apache/beam/gradle/BeamModulePlugin.groovy @@ -1291,8 +1291,19 @@ class BeamModulePlugin implements Plugin { // hadoop uses an old version of logback with CVE reports // force all transitive logback deps to a newer one - force "ch.qos.logback:logback-classic:$logback_version" - force "ch.qos.logback:logback-core:$logback_version" + // When running tests with Java 8, use Java 8 compatible version only for test runtime configurations + // (not compile configurations to avoid dependency resolution failures) + // Only apply Java 8 compatible logback to explicit test runtime configurations, not compile/testCompile/testImplementation + def configName = config.getName().toLowerCase() + def isTestRuntimeConfig = (configName == 'testruntimeclasspath' || + configName == 'testruntimeonly' || + configName == 'testruntimemigration' || + configName == 'shadowtestruntimeclasspath') + // Use logback 1.4.14 for Java 8 test runtime (last stable 1.4.x that supports Java 8) + // Logback 1.5.x requires Java 11+, so we must use 1.4.x when running tests with Java 8 + def logbackVersionToUse = (isTestRuntimeConfig && project.findProperty('testJavaVersion') == '8') ? '1.4.14' : logback_version + force "ch.qos.logback:logback-classic:$logbackVersionToUse" + force "ch.qos.logback:logback-core:$logbackVersionToUse" } } } @@ -1663,21 +1674,57 @@ class BeamModulePlugin implements Plugin { String ver = project.getProperty('testJavaVersion') def testJavaHome = project.getProperty("java${ver}Home") - // redirect java compiler to specified version for compileTestJava only + def cleanTestClassesTask = project.tasks.register("cleanTestClassesForJava${ver}") { + outputs.upToDateWhen { false } + doFirst { + project.sourceSets.test.output.classesDirs.each { dir -> + if (dir.exists()) { + project.delete(dir) + } + } + } + } project.tasks.compileTestJava { setCompileAndRuntimeJavaVersion(options.compilerArgs, ver) + // Validate javaHome exists before configuring fork options + def javaHomeFile = testJavaHome as File + if (!javaHomeFile.exists()) { + throw new GradleException("testJavaVersion=${ver} java${ver}Home directory does not exist: ${javaHomeFile}") + } + // Use setJavaVerOptions to configure fork with the correct Java version + // Note: setJavaVerOptions uses findProperty, but we've already validated it exists above project.ext.setJavaVerOptions(options, ver) + if (ver == '25') { // TODO: Upgrade errorprone version to support Java25. Currently compile crashes // java.lang.NoSuchFieldError: Class com.sun.tools.javac.code.TypeTag does not have member field // 'com.sun.tools.javac.code.TypeTag UNKNOWN' options.errorprone.enabled = false } + outputs.upToDateWhen { false } + dependsOn cleanTestClassesTask + doFirst { + // Ensure fork is enabled (setJavaVerOptions should have done this, but double-check as fallback) + if (!options.fork) { + options.fork = true + options.forkOptions.javaHome = javaHomeFile + } + } } - // redirect java runtime to specified version for running tests project.tasks.withType(Test).configureEach { useJUnit() executable = "${testJavaHome}/bin/java" + dependsOn cleanTestClassesTask + dependsOn project.tasks.compileTestJava + } + project.afterEvaluate { + project.tasks.withType(Test).configureEach { testTask -> + if (testJavaHome) { + testTask.executable = "${testJavaHome}/bin/java" + } + testTask.dependsOn cleanTestClassesTask + testTask.dependsOn project.tasks.compileTestJava + } } }