From ce9015495378f0b83efbf9a33b595c1549c5dce1 Mon Sep 17 00:00:00 2001 From: Brian Clozel Date: Wed, 21 May 2025 09:52:49 +0200 Subject: [PATCH] Compile Spring for GraphQL with Java 24 But targeting a Java 17 baseline for bytecode version. Closes gh-1206 --- .../build/conventions/JavaConventions.java | 82 +++++++++++++++---- spring-graphql-docs/build.gradle | 10 ++- 2 files changed, 74 insertions(+), 18 deletions(-) diff --git a/buildSrc/src/main/java/org/springframework/graphql/build/conventions/JavaConventions.java b/buildSrc/src/main/java/org/springframework/graphql/build/conventions/JavaConventions.java index b78cd3d9..1219a75b 100644 --- a/buildSrc/src/main/java/org/springframework/graphql/build/conventions/JavaConventions.java +++ b/buildSrc/src/main/java/org/springframework/graphql/build/conventions/JavaConventions.java @@ -24,7 +24,10 @@ import org.gradle.api.Plugin; import org.gradle.api.Project; import org.gradle.api.plugins.JavaLibraryPlugin; import org.gradle.api.plugins.JavaPlugin; +import org.gradle.api.plugins.JavaPluginExtension; import org.gradle.api.tasks.compile.JavaCompile; +import org.gradle.jvm.toolchain.JavaLanguageVersion; +import org.gradle.jvm.toolchain.JvmVendorSpec; /** * {@link Plugin} that applies conventions for compiling Java sources in Spring Framework. @@ -39,6 +42,19 @@ public class JavaConventions { private static final List TEST_COMPILER_ARGS; + /** + * The Java version we should use as the JVM baseline for building the project. + *

NOTE: If you update this value, you should also update the value used in + * the {@code javadoc} task in {@code framework-api.gradle}. + */ + private static final JavaLanguageVersion DEFAULT_LANGUAGE_VERSION = JavaLanguageVersion.of(24); + + /** + * The Java version we should use as the baseline for the compiled bytecode + * (the "-release" compiler argument). + */ + private static final JavaLanguageVersion DEFAULT_RELEASE_VERSION = JavaLanguageVersion.of(17); + static { List commonCompilerArgs = Arrays.asList( "-Xlint:serial", "-Xlint:cast", "-Xlint:classfile", "-Xlint:dep-ann", @@ -59,28 +75,64 @@ public class JavaConventions { } public void apply(Project project) { - project.getPlugins().withType(JavaLibraryPlugin.class, (javaPlugin) -> applyJavaCompileConventions(project)); + project.getPlugins().withType(JavaLibraryPlugin.class, (javaPlugin) -> { + applyToolchainConventions(project); + applyJavaCompileConventions(project); + }); } /** - * Applies the common Java compiler options for main sources, test fixture sources, and + * Configure the Toolchain support for the project. + * @param project the current project + */ + private static void applyToolchainConventions(Project project) { + project.getExtensions().getByType(JavaPluginExtension.class).toolchain(toolchain -> { + toolchain.getVendor().set(JvmVendorSpec.BELLSOFT); + toolchain.getLanguageVersion().set(DEFAULT_LANGUAGE_VERSION); + }); + } + + /** + * Apply the common Java compiler options for main sources, test fixture sources, and * test sources. * @param project the current project */ private void applyJavaCompileConventions(Project project) { - project.getTasks().withType(JavaCompile.class) - .matching((compileTask) -> compileTask.getName().equals(JavaPlugin.COMPILE_JAVA_TASK_NAME)) - .forEach((compileTask) -> { - compileTask.getOptions().setCompilerArgs(COMPILER_ARGS); - compileTask.getOptions().setEncoding("UTF-8"); - }); - project.getTasks().withType(JavaCompile.class) - .matching((compileTask) -> compileTask.getName().equals(JavaPlugin.COMPILE_TEST_JAVA_TASK_NAME) - || compileTask.getName().equals("compileTestFixturesJava")) - .forEach((compileTask) -> { - compileTask.getOptions().setCompilerArgs(TEST_COMPILER_ARGS); - compileTask.getOptions().setEncoding("UTF-8"); - }); + project.afterEvaluate(p -> { + p.getTasks().withType(JavaCompile.class) + .matching(compileTask -> compileTask.getName().startsWith(JavaPlugin.COMPILE_JAVA_TASK_NAME)) + .forEach(compileTask -> { + compileTask.getOptions().setCompilerArgs(COMPILER_ARGS); + compileTask.getOptions().setEncoding("UTF-8"); + setJavaRelease(compileTask); + }); + p.getTasks().withType(JavaCompile.class) + .matching(compileTask -> compileTask.getName().startsWith(JavaPlugin.COMPILE_TEST_JAVA_TASK_NAME) + || compileTask.getName().equals("compileTestFixturesJava")) + .forEach(compileTask -> { + compileTask.getOptions().setCompilerArgs(TEST_COMPILER_ARGS); + compileTask.getOptions().setEncoding("UTF-8"); + setJavaRelease(compileTask); + }); + + }); + } + + /** + * We should pick the {@link #DEFAULT_RELEASE_VERSION} for all compiled classes, + * unless the current task is compiling multi-release JAR code with a higher version. + */ + private void setJavaRelease(JavaCompile task) { + int defaultVersion = DEFAULT_RELEASE_VERSION.asInt(); + int releaseVersion = defaultVersion; + int compilerVersion = task.getJavaCompiler().get().getMetadata().getLanguageVersion().asInt(); + for (int version = defaultVersion ; version <= compilerVersion ; version++) { + if (task.getName().contains("Java" + version)) { + releaseVersion = version; + break; + } + } + task.getOptions().getRelease().set(releaseVersion); } } diff --git a/spring-graphql-docs/build.gradle b/spring-graphql-docs/build.gradle index 35b9580d..985c6104 100644 --- a/spring-graphql-docs/build.gradle +++ b/spring-graphql-docs/build.gradle @@ -41,11 +41,11 @@ javadoc { enabled = false } - /** * Produce Javadoc for all Spring for GraphQL modules in "build/docs/javadoc" */ -task api(type: Javadoc) { +tasks.register("api", Javadoc) { + group = "Documentation" description = "Generates aggregated Javadoc API documentation." title = "${rootProject.description} ${version} API" @@ -74,6 +74,9 @@ task api(type: Javadoc) { }.sum() maxMemory = "1024m" destinationDir = file("$buildDir/docs/javadoc") + javadocTool.set(javaToolchains.javadocToolFor({ + languageVersion = JavaLanguageVersion.of(24) + })) } @@ -98,7 +101,8 @@ tasks.named("antora") { /** * Zip all docs into a single archive */ -task docsZip(type: Zip, dependsOn: ['api']) { +tasks.register("docsZip", Zip) { + dependsOn = ['api'] group = "Distribution" description = "Builds -${archiveClassifier} archive containing api and reference " + "for deployment at https://docs.spring.io/spring-graphql/docs."