diff --git a/build.gradle b/build.gradle index c8a38eaec4..b22ee53a89 100644 --- a/build.gradle +++ b/build.gradle @@ -26,6 +26,7 @@ plugins { id 'biz.aQute.bnd' version '6.3.1' apply false id 'org.checkerframework' version '0.6.25' + id 'org.hibernate.orm.build.jdks' id 'io.github.gradle-nexus.publish-plugin' version '1.1.0' @@ -46,9 +47,7 @@ task release { "themselves if they have any release-related activities to perform" doFirst { - def javaVersionsInUse = [gradle.ext.javaVersions.main.compiler, gradle.ext.javaVersions.main.release, - gradle.ext.javaVersions.test.compiler, gradle.ext.javaVersions.test.release, - gradle.ext.javaVersions.test.launcher].toSet() + def javaVersionsInUse = jdkVersions.allVersions if ( javaVersionsInUse != [JavaLanguageVersion.of( 11 )].toSet() ) { throw new IllegalStateException( "Please use JDK 11 to perform the release. Currently using: ${javaVersionsInUse}" ) } diff --git a/gradle/java-module.gradle b/gradle/java-module.gradle index f3bc243101..0258834cb0 100644 --- a/gradle/java-module.gradle +++ b/gradle/java-module.gradle @@ -25,11 +25,10 @@ apply from: rootProject.file( 'gradle/module.gradle' ) apply from: rootProject.file( 'gradle/libraries.gradle' ) apply from: rootProject.file( 'gradle/databases.gradle' ) -apply plugin: 'org.hibernate.orm.database-service' - apply plugin: 'java-library' apply plugin: 'biz.aQute.bnd.builder' apply plugin: 'org.hibernate.orm.database-service' +apply plugin: 'org.hibernate.orm.build.java-module' apply plugin: 'org.checkerframework' @@ -159,58 +158,6 @@ tasks.withType( JavaCompile ) { // ] } -if ( !gradle.ext.javaToolchainEnabled ) { - tasks.compileJava.configure { - sourceCompatibility = JavaVersion.toVersion( gradle.ext.javaVersions.main.release ) - targetCompatibility = JavaVersion.toVersion( gradle.ext.javaVersions.main.release ) - } - tasks.compileTestJava.configure { - sourceCompatibility = JavaVersion.toVersion( gradle.ext.javaVersions.test.release ) - targetCompatibility = JavaVersion.toVersion( gradle.ext.javaVersions.test.release ) - } -} -else { - // Configure generated bytecode - // "sourceCompatibility" is not supported with toolchains. We have to work around that limitation. - tasks.compileJava.configure { - options.release = gradle.ext.javaVersions.main.release.asInt() - // Needs add-opens because of https://github.com/gradle/gradle/issues/15538 - options.forkOptions.jvmArgs.addAll( ["--add-opens", "jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED"] ) - } - tasks.compileTestJava.configure { - options.release = gradle.ext.javaVersions.test.release.asInt() - // Needs add-opens because of https://github.com/gradle/gradle/issues/15538 - options.forkOptions.jvmArgs.addAll( ["--add-opens", "jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED"] ) - } - - // Configure version of Java tools - java { - toolchain { - languageVersion = gradle.ext.javaVersions.main.compiler - } - } - tasks.compileTestJava { - javaCompiler = javaToolchains.compilerFor { - languageVersion = gradle.ext.javaVersions.test.compiler - } - } - - // Configure JVM Options - // Display version of Java tools - tasks.withType( JavaCompile ).configureEach { - options.forkOptions.jvmArgs.addAll( getProperty( 'toolchain.compiler.jvmargs' ).toString().split( ' ' ) ) - doFirst { - logger.lifecycle "Compiling with '${javaCompiler.get().metadata.installationPath}'" - } - } - tasks.withType( Javadoc ).configureEach { - options.setJFlags( getProperty( 'toolchain.javadoc.jvmargs' ).toString().split( ' ' ).toList().findAll( { !it.isEmpty() } ) ) - doFirst { - logger.lifecycle "Generating javadoc with '${javadocTool.get().metadata.installationPath}'" - } - } -} - task compile(dependsOn: [compileJava, processResources, compileTestJava, processTestResources] ) @@ -231,7 +178,7 @@ if ( toolsJar.exists() ) { // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Testing -if ( gradle.ext.javaToolchainEnabled ) { +if ( jdkVersions.explicitlyConfigured ) { tasks.test { // Configure version of Java tools javaLauncher = javaToolchains.launcherFor { @@ -363,7 +310,7 @@ test { // and those classes always have bytecode matching the version of the launcher. // So for example, when using a JDK22 launcher and compiling tests with --release 21, // Bytebuddy will still encounter classes with Java 22 bytecode. - if ( gradle.ext.javaVersions.test.launcher.asInt() >= 22 ) { + if ( jdkVersions.test.launcher.asInt() >= 22 ) { logger.warn( "The version of Java bytecode that will be tested is not supported by Bytebuddy by default. " + " Setting 'net.bytebuddy.experimental=true'." ) systemProperty 'net.bytebuddy.experimental', true @@ -537,7 +484,7 @@ task forbiddenApisSystemOut(type: CheckForbiddenApis, dependsOn: compileJava) { } task forbiddenApisUnsafe(type: CheckForbiddenApis, dependsOn: compileJava) { - bundledSignatures += "jdk-unsafe-${gradle.ext.baselineJavaVersion}".toString() + bundledSignatures += "jdk-unsafe-${jdkVersions.baseline}".toString() // unfortunately we currently have many uses of default Locale implicitly (~370) which need to be fixed // before we can fully enabled this check diff --git a/hibernate-core/hibernate-core.gradle b/hibernate-core/hibernate-core.gradle index dd13d3cfe3..3fbf5cdb15 100644 --- a/hibernate-core/hibernate-core.gradle +++ b/hibernate-core/hibernate-core.gradle @@ -254,7 +254,7 @@ tasks.withType( Test.class ).each { test -> } // Tests with records -if ( gradle.ext.javaVersions.test.release.asInt() >= 17 && gradle.ext.javaToolchainEnabled ) { +if ( jdkVersions.test.release.asInt() >= 17 && jdkVersions.explicit ) { // Add a new source set, which contains tests that can run on JDK17+ sourceSets { diff --git a/local-build-plugins/build.gradle b/local-build-plugins/build.gradle index 445de243db..53e2413a84 100644 --- a/local-build-plugins/build.gradle +++ b/local-build-plugins/build.gradle @@ -68,6 +68,14 @@ gradlePlugin { id = 'org.hibernate.orm.build.properties' implementationClass = 'org.hibernate.orm.properties.ConfigPropertyCollectorPlugin' } + jdkVersionsPlugin { + id = 'org.hibernate.orm.build.jdks' + implementationClass = 'org.hibernate.orm.toolchains.JdkVersionPlugin' + } + javaModulePlugin { + id = 'org.hibernate.orm.build.java-module' + implementationClass = 'org.hibernate.orm.toolchains.JavaModulePlugin' + } } } diff --git a/local-build-plugins/src/main/java/org/hibernate/orm/toolchains/JavaModulePlugin.java b/local-build-plugins/src/main/java/org/hibernate/orm/toolchains/JavaModulePlugin.java new file mode 100644 index 0000000000..ab48bab30c --- /dev/null +++ b/local-build-plugins/src/main/java/org/hibernate/orm/toolchains/JavaModulePlugin.java @@ -0,0 +1,151 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html. + */ +package org.hibernate.orm.toolchains; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; +import javax.inject.Inject; + +import org.gradle.api.Action; +import org.gradle.api.JavaVersion; +import org.gradle.api.Plugin; +import org.gradle.api.Project; +import org.gradle.api.Task; +import org.gradle.api.plugins.JavaPluginExtension; +import org.gradle.api.tasks.SourceSet; +import org.gradle.api.tasks.SourceSetContainer; +import org.gradle.api.tasks.compile.JavaCompile; +import org.gradle.api.tasks.javadoc.Javadoc; +import org.gradle.jvm.toolchain.JavaLanguageVersion; +import org.gradle.jvm.toolchain.JavaToolchainService; +import org.gradle.jvm.toolchain.JavaToolchainSpec; + +import static java.util.Arrays.asList; + +/** + * @author Steve Ebersole + */ +public class JavaModulePlugin implements Plugin { + private final JavaToolchainService toolchainService; + + @Inject + public JavaModulePlugin(JavaToolchainService toolchainService) { + this.toolchainService = toolchainService; + } + + @Override + public void apply(Project project) { + project.getPluginManager().apply( JdkVersionPlugin.class ); + + final JdkVersionConfig jdkVersionsConfig = project.getExtensions().getByType( JdkVersionConfig.class ); + + final JavaPluginExtension javaPluginExtension = project.getExtensions().getByType( JavaPluginExtension.class ); + + final SourceSetContainer sourceSets = javaPluginExtension.getSourceSets(); + final SourceSet mainSourceSet = sourceSets.getByName( SourceSet.MAIN_SOURCE_SET_NAME ); + final SourceSet testSourceSet = sourceSets.getByName( SourceSet.TEST_SOURCE_SET_NAME ); + + final JavaCompile mainCompileTask = (JavaCompile) project.getTasks().getByName( mainSourceSet.getCompileJavaTaskName() ); + mainCompileTask.setSourceCompatibility( jdkVersionsConfig.getTestCompileVersion().toString() ); + mainCompileTask.setTargetCompatibility( jdkVersionsConfig.getTestCompileVersion().toString() ); + + final JavaCompile testCompileTask = (JavaCompile) project.getTasks().getByName( testSourceSet.getCompileJavaTaskName() ); + testCompileTask.setSourceCompatibility( jdkVersionsConfig.getTestCompileVersion().toString() ); + testCompileTask.setTargetCompatibility( jdkVersionsConfig.getTestCompileVersion().toString() ); + + if ( jdkVersionsConfig.isExplicit() ) { + javaPluginExtension.getToolchain().getLanguageVersion().set( jdkVersionsConfig.getMainCompileVersion() ); + + prepareCompileTask( mainCompileTask, jdkVersionsConfig.getMainCompileVersion() ); + prepareCompileTask( testCompileTask, jdkVersionsConfig.getTestCompileVersion() ); + + testCompileTask.getJavaCompiler().set( + toolchainService.compilerFor( new Action() { + @Override + public void execute(JavaToolchainSpec javaToolchainSpec) { + javaToolchainSpec.getLanguageVersion().set( jdkVersionsConfig.getTestCompileVersion() ); + } + } ) + ); + + project.getTasks().withType( JavaCompile.class ).configureEach( new Action() { + @Override + public void execute(JavaCompile compileTask) { + getJvmArgs( compileTask ).addAll( + Arrays.asList( + project.property( "toolchain.compiler.jvmargs" ).toString().split( " " ) + ) + ); + compileTask.doFirst( + new Action() { + @Override + public void execute(Task task) { + project.getLogger().lifecycle( + "Compiling with '%s'", + compileTask.getJavaCompiler().get().getMetadata().getInstallationPath() + ); + } + } + ); + } + } ); + + project.getTasks().withType( Javadoc.class ).configureEach( (javadocTask) -> { + javadocTask.getOptions().setJFlags( javadocFlags( project ) ); + javadocTask.doFirst( new Action() { + @Override + public void execute(Task task) { + project.getLogger().lifecycle( + "Generating javadoc with '%s'", + javadocTask.getJavadocTool().get().getMetadata().getInstallationPath() + ); + } + } ); + } ); + } + } + + private static List javadocFlags(Project project) { + final String jvmArgs = project.property( "toolchain.javadoc.jvmargs" ).toString(); + final String[] splits = jvmArgs.split( " " ); + return Arrays.asList( splits ).stream().filter( (split) -> !split.isEmpty() ).collect( Collectors.toList() ); + } + + private void prepareCompileTask(JavaCompile compileTask, JavaLanguageVersion version) { + compileTask.getJavaCompiler().set( + toolchainService.compilerFor( new Action() { + @Override + public void execute(JavaToolchainSpec javaToolchainSpec) { + javaToolchainSpec.getLanguageVersion().set( version ); + } + } ) + ); + + compileTask.getOptions().getRelease().set( version.asInt() ); + + // Needs add-opens because of https://github.com/gradle/gradle/issues/15538 + getJvmArgs( compileTask ).addAll( asList( "--add-opens", "jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED" ) ); + } + + public static List getJvmArgs(JavaCompile compileTask) { + final List existing = compileTask + .getOptions() + .getForkOptions() + .getJvmArgs(); + if ( existing == null ) { + final List target = new ArrayList<>(); + compileTask.getOptions().getForkOptions().setJvmArgs( target ); + return target; + } + else { + return existing; + } + } +} diff --git a/local-build-plugins/src/main/java/org/hibernate/orm/toolchains/JdkVersionConfig.java b/local-build-plugins/src/main/java/org/hibernate/orm/toolchains/JdkVersionConfig.java new file mode 100644 index 0000000000..490440f27f --- /dev/null +++ b/local-build-plugins/src/main/java/org/hibernate/orm/toolchains/JdkVersionConfig.java @@ -0,0 +1,286 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html. + */ +package org.hibernate.orm.toolchains; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +import org.gradle.StartParameter; +import org.gradle.api.Project; +import org.gradle.api.artifacts.VersionCatalog; +import org.gradle.api.artifacts.VersionConstraint; +import org.gradle.api.initialization.Settings; +import org.gradle.jvm.toolchain.JavaLanguageVersion; + +import org.jetbrains.annotations.NotNull; + +import static java.util.Objects.requireNonNullElse; + +/** + * Describes the JDK versions of interest to the Hibernate build + * + * @author Steve Ebersole + */ +public class JdkVersionConfig { + public static final String DSL_NAME = "jdkVersions"; + public static final String MAIN_JDK_VERSION = "main.jdk.version"; + public static final String TEST_JDK_VERSION = "test.jdk.version"; + + private final boolean explicit; + private final JavaLanguageVersion baseline; + private final MainJdks main; + private final TestJdks test; + + public JdkVersionConfig( + boolean explicit, + JavaLanguageVersion baseline, + JavaLanguageVersion mainCompileVersion, + JavaLanguageVersion mainReleaseVersion, + JavaLanguageVersion testCompileVersion, + JavaLanguageVersion testReleaseVersion, + JavaLanguageVersion testLauncherVersion) { + this.explicit = explicit; + this.baseline = baseline; + this.main = new MainJdks( mainCompileVersion, mainReleaseVersion ); + this.test = new TestJdks( testCompileVersion, testReleaseVersion, testLauncherVersion ); + } + + public boolean isExplicitlyConfigured() { + return explicit; + } + + public boolean isExplicit() { + return explicit; + } + + public JavaLanguageVersion getBaselineVersion() { + return baseline; + } + + public JavaLanguageVersion getBaseline() { + return baseline; + } + + public MainJdks getMain() { + return main; + } + + public TestJdks getTest() { + return test; + } + + public JavaLanguageVersion getMainCompileVersion() { + return main.getCompile(); + } + + public JavaLanguageVersion getMainReleaseVersion() { + return main.getRelease(); + } + + public JavaLanguageVersion getTestCompileVersion() { + return test.getCompile(); + } + + public JavaLanguageVersion getTestReleaseVersion() { + return test.getRelease(); + } + + public JavaLanguageVersion getTestLauncherVersion() { + return test.getLauncher(); + } + + public Set getAllVersions() { + final HashSet versions = new HashSet<>(); + versions.add( getMainCompileVersion() ); + versions.add( getMainReleaseVersion() ); + versions.add( getTestCompileVersion() ); + versions.add( getTestReleaseVersion() ); + versions.add( getTestLauncherVersion() ); + return versions; + } + + @NotNull + public static JdkVersionConfig createVersionConfig( + JavaLanguageVersion explicitMainVersion, + JavaLanguageVersion explicitTestVersion, + JavaLanguageVersion gradleJdkVersion, + JavaLanguageVersion baselineJdkVersion, + JavaLanguageVersion maxSupportedJdkVersion) { + final boolean explicitlyConfigured = explicitMainVersion != null || explicitTestVersion != null; + + final JavaLanguageVersion mainCompileVersion; + final JavaLanguageVersion mainReleaseVersion; + final JavaLanguageVersion testCompileVersion; + final JavaLanguageVersion testReleaseVersion; + final JavaLanguageVersion testLauncherVersion; + + if ( explicitlyConfigured ) { + mainCompileVersion = requireNonNullElse( explicitMainVersion, baselineJdkVersion ); + testCompileVersion = requireNonNullElse( explicitTestVersion, baselineJdkVersion ); + mainReleaseVersion = baselineJdkVersion; + + if ( testCompileVersion.asInt() > gradleJdkVersion.asInt() ) { + System.out.println( + "[WARN] Gradle does not support bytecode version '${testCompilerVersion}'." + + " Forcing test bytecode to version ${GRADLE_MAX_SUPPORTED_BYTECODE_VERSION}." + ); + testReleaseVersion = maxSupportedJdkVersion; + } + else { + testReleaseVersion = testCompileVersion; + } + + testLauncherVersion = testCompileVersion; + + return new JdkVersionConfig( + false, + baselineJdkVersion, + mainCompileVersion, + mainReleaseVersion, + testCompileVersion, + testReleaseVersion, + testLauncherVersion + ); + } + else { + // Not testing a particular JDK version: we will use the same JDK used to run Gradle. + // We disable toolchains for convenience, so that anyone can just run the build with their own JDK + // without any additional options and without downloading the whole JDK. + if ( gradleJdkVersion.asInt() > maxSupportedJdkVersion.asInt() ) { + System.out.println( + "[WARN] Gradle does not support this JDK, because it is too recent; build is likely to fail." + + " To avoid failures, you should use an older Java version when running Gradle, and rely on toolchains." + + " To that end, specify the version of Java you want to run tests with using property 'test.jdk.version'," + + " and specify the path to JDK8 *and* a JDK of the test version using property 'org.gradle.java.installations.paths'." + + " Example:" + + " ./gradlew build -Ptest.jdk.version=15 -Porg.gradle.java.installations.paths=$SDKMAN_CANDIDATES_DIR/java/15.0.1-open,$SDKMAN_CANDIDATES_DIR/java/8" + ); + } + + return new JdkVersionConfig( + false, + baselineJdkVersion, + gradleJdkVersion, + baselineJdkVersion, + gradleJdkVersion, + baselineJdkVersion, + gradleJdkVersion + ); + } + } + + @NotNull + private static JavaLanguageVersion getJavaLanguageVersion(VersionCatalog jdks, String entryName) { + final VersionConstraint versionConstraint = jdks.findVersion( entryName ).orElseThrow(); + return JavaLanguageVersion.of( versionConstraint.getRequiredVersion() ); + } + + public static JavaLanguageVersion extractVersion(Settings settings, String propertyName) { + final StartParameter startParameters = settings.getGradle().getStartParameter(); + final String projectProp = startParameters.getProjectProperties().get( propertyName ); + if ( projectProp != null ) { + return JavaLanguageVersion.of( projectProp ); + } + + final String sysProp = startParameters.getSystemPropertiesArgs().get( propertyName ); + if ( sysProp != null ) { + return JavaLanguageVersion.of( sysProp ); + } + + return null; + } + + public static JavaLanguageVersion extractVersion(Project project, String propertyName) { + final Object projectProp = project.getProperties().get( propertyName ); + if ( projectProp != null ) { + return JavaLanguageVersion.of( projectProp.toString() ); + } + + final Object sysProp = System.getProperties().get( propertyName ); + if ( sysProp != null ) { + return JavaLanguageVersion.of( sysProp.toString() ); + } + + return null; + } + + + + + public static class MainJdks implements JdkVersionCombo { + private final JavaLanguageVersion compileVersion; + private final JavaLanguageVersion releaseVersion; + + public MainJdks(JavaLanguageVersion compileVersion, JavaLanguageVersion releaseVersion) { + this.compileVersion = compileVersion; + this.releaseVersion = releaseVersion; + } + + @Override + public JavaLanguageVersion getCompile() { + return compileVersion; + } + + public JavaLanguageVersion getCompiler() { + return compileVersion; + } + + @Override + public JavaLanguageVersion getRelease() { + return releaseVersion; + } + + @Override + public String toString() { + return "[compile: " + compileVersion + ", release:" + releaseVersion + "]"; + } + } + + public static class TestJdks implements JdkVersionCombo { + private final JavaLanguageVersion compileVersion; + private final JavaLanguageVersion releaseVersion; + private final JavaLanguageVersion launcherVersion; + + public TestJdks( + JavaLanguageVersion compileVersion, + JavaLanguageVersion releaseVersion, + JavaLanguageVersion launcherVersion) { + this.compileVersion = compileVersion; + this.releaseVersion = releaseVersion; + this.launcherVersion = launcherVersion; + } + + public JavaLanguageVersion getCompiler() { + return compileVersion; + } + + @Override + public JavaLanguageVersion getCompile() { + return compileVersion; + } + + @Override + public JavaLanguageVersion getRelease() { + return releaseVersion; + } + + public JavaLanguageVersion getLauncher() { + return launcherVersion; + } + + @Override + public String toString() { + return "[compile: " + compileVersion + ", release:" + releaseVersion + ", launcher: " + launcherVersion + "]"; + } + } + + public interface JdkVersionCombo { + JavaLanguageVersion getCompile(); + JavaLanguageVersion getRelease(); + } +} diff --git a/local-build-plugins/src/main/java/org/hibernate/orm/toolchains/JdkVersionPlugin.java b/local-build-plugins/src/main/java/org/hibernate/orm/toolchains/JdkVersionPlugin.java new file mode 100644 index 0000000000..e9ad316048 --- /dev/null +++ b/local-build-plugins/src/main/java/org/hibernate/orm/toolchains/JdkVersionPlugin.java @@ -0,0 +1,72 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html. + */ +package org.hibernate.orm.toolchains; + +import javax.inject.Inject; + +import org.gradle.api.Action; +import org.gradle.api.JavaVersion; +import org.gradle.api.Plugin; +import org.gradle.api.Project; +import org.gradle.api.artifacts.VersionCatalog; +import org.gradle.api.artifacts.VersionCatalogsExtension; +import org.gradle.api.artifacts.VersionConstraint; +import org.gradle.api.plugins.JavaPluginExtension; +import org.gradle.api.tasks.SourceSet; +import org.gradle.api.tasks.SourceSetContainer; +import org.gradle.api.tasks.compile.JavaCompile; +import org.gradle.jvm.toolchain.JavaLanguageVersion; +import org.gradle.jvm.toolchain.JavaToolchainService; +import org.gradle.jvm.toolchain.JavaToolchainSpec; + +import org.jetbrains.annotations.NotNull; + +import static org.hibernate.orm.toolchains.JdkVersionConfig.MAIN_JDK_VERSION; +import static org.hibernate.orm.toolchains.JdkVersionConfig.TEST_JDK_VERSION; +import static org.hibernate.orm.toolchains.JdkVersionConfig.createVersionConfig; +import static org.hibernate.orm.toolchains.JdkVersionConfig.extractVersion; + +/** + * @author Steve Ebersole + */ +public class JdkVersionPlugin implements Plugin { + private final JavaToolchainService toolchainService; + + @Inject + public JdkVersionPlugin(JavaToolchainService toolchainService) { + this.toolchainService = toolchainService; + } + + @Override + public void apply(Project project) { + final JavaLanguageVersion explicitMainVersion = extractVersion( project, MAIN_JDK_VERSION ); + final JavaLanguageVersion explicitTestVersion = extractVersion( project, TEST_JDK_VERSION ); + + final JavaLanguageVersion gradleJdkVersion = JavaLanguageVersion.of( JavaVersion.current().getMajorVersion() ); + final VersionCatalogsExtension versionCatalogs = project.getExtensions().getByType( VersionCatalogsExtension.class ); + final VersionCatalog jdkVersions = versionCatalogs.named( "jdks" ); + final JavaLanguageVersion baselineJdkVersion = getJavaLanguageVersion( jdkVersions, "baseline" ); + final JavaLanguageVersion maxSupportedJdkVersion = getJavaLanguageVersion( jdkVersions, "maxSupportedBytecode" ); + + final JdkVersionConfig jdkVersionConfig = createVersionConfig( + explicitMainVersion, + explicitTestVersion, + gradleJdkVersion, + baselineJdkVersion, + maxSupportedJdkVersion + ); + + project.getExtensions().add( JdkVersionConfig.DSL_NAME, jdkVersionConfig ); + JdkVersionsLogging.logVersions( jdkVersionConfig ); + } + + @NotNull + private static JavaLanguageVersion getJavaLanguageVersion(VersionCatalog jdks, String entryName) { + final VersionConstraint versionConstraint = jdks.findVersion( entryName ).orElseThrow(); + return JavaLanguageVersion.of( versionConstraint.getRequiredVersion() ); + } +} diff --git a/local-build-plugins/src/main/java/org/hibernate/orm/toolchains/JdkVersionSettingsPlugin.java b/local-build-plugins/src/main/java/org/hibernate/orm/toolchains/JdkVersionSettingsPlugin.java new file mode 100644 index 0000000000..66b3f19dbd --- /dev/null +++ b/local-build-plugins/src/main/java/org/hibernate/orm/toolchains/JdkVersionSettingsPlugin.java @@ -0,0 +1,60 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html. + */ +package org.hibernate.orm.toolchains; + +import org.gradle.api.JavaVersion; +import org.gradle.api.Plugin; +import org.gradle.api.artifacts.VersionCatalog; +import org.gradle.api.artifacts.VersionConstraint; +import org.gradle.api.initialization.Settings; +import org.gradle.api.plugins.ExtraPropertiesExtension; +import org.gradle.jvm.toolchain.JavaLanguageVersion; + +import org.jetbrains.annotations.NotNull; + +import static org.hibernate.orm.toolchains.JdkVersionConfig.MAIN_JDK_VERSION; +import static org.hibernate.orm.toolchains.JdkVersionConfig.TEST_JDK_VERSION; +import static org.hibernate.orm.toolchains.JdkVersionConfig.createVersionConfig; +import static org.hibernate.orm.toolchains.JdkVersionConfig.extractVersion; + +/** + * @author Steve Ebersole + */ +public class JdkVersionSettingsPlugin implements Plugin { + @Override + public void apply(Settings settings) { + final JavaLanguageVersion explicitMainVersion = extractVersion( settings, MAIN_JDK_VERSION ); + final JavaLanguageVersion explicitTestVersion = extractVersion( settings, TEST_JDK_VERSION ); + + final JavaLanguageVersion gradleJdkVersion = JavaLanguageVersion.of( JavaVersion.current().getMajorVersion() ); + final JavaLanguageVersion baselineJdkVersion; + final JavaLanguageVersion maxSupportedJdkVersion; +// final VersionCatalogsExtension versionCatalogs = settings.getExtensions().getByType( VersionCatalogsExtension.class ); +// final VersionCatalog jdkVersions = versionCatalogs.named( "jdks" ); +// baselineJdkVersion = getJavaLanguageVersion( jdkVersions, "baseline" ); +// maxSupportedJdkVersion = getJavaLanguageVersion( jdkVersions, "maxSupportedBytecode" ); + baselineJdkVersion = JavaLanguageVersion.of( "11" ); + maxSupportedJdkVersion = JavaLanguageVersion.of( "17" ); + + final JdkVersionConfig jdkVersionConfig = createVersionConfig( + explicitMainVersion, + explicitTestVersion, + gradleJdkVersion, + baselineJdkVersion, + maxSupportedJdkVersion + ); + + settings.getGradle().getExtensions().add( JdkVersionConfig.DSL_NAME, jdkVersionConfig ); + JdkVersionsLogging.logVersions( jdkVersionConfig ); + } + + @NotNull + private static JavaLanguageVersion getJavaLanguageVersion(VersionCatalog jdks, String entryName) { + final VersionConstraint versionConstraint = jdks.findVersion( entryName ).orElseThrow(); + return JavaLanguageVersion.of( versionConstraint.getRequiredVersion() ); + } +} diff --git a/local-build-plugins/src/main/java/org/hibernate/orm/toolchains/JdkVersionsLogging.java b/local-build-plugins/src/main/java/org/hibernate/orm/toolchains/JdkVersionsLogging.java new file mode 100644 index 0000000000..4c224adb9f --- /dev/null +++ b/local-build-plugins/src/main/java/org/hibernate/orm/toolchains/JdkVersionsLogging.java @@ -0,0 +1,43 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html. + */ +package org.hibernate.orm.toolchains; + +/** + * @author Steve Ebersole + */ +public class JdkVersionsLogging { + private static boolean logged = false; + + public static void logVersions(JdkVersionConfig jdkVersionConfig) { + if ( logged ) { + return; + } + + logged = true; + + final String implicitExplicitString = jdkVersionConfig.isExplicit() ? "explicit" : "implicit"; + + System.out.println( + "Java versions for main code: " + jdkVersionConfig.getMain() + + " (" + implicitExplicitString + ")" + ); + System.out.println( + "Java versions for test code: " + jdkVersionConfig.getTest() + + " (" + implicitExplicitString + ")" + ); + } + + public static void logOnce(String message) { + if ( logged ) { + return; + } + + logged = true; + + System.out.println( message ); + } +} diff --git a/release/release.gradle b/release/release.gradle index ccc72b6b24..952e7bc657 100644 --- a/release/release.gradle +++ b/release/release.gradle @@ -12,6 +12,7 @@ import groovy.json.JsonSlurper apply from: rootProject.file( 'gradle/module.gradle' ) apply plugin: 'org.hibernate.orm.build.doc-pub' +apply plugin: 'org.hibernate.orm.build.jdks' apply plugin: 'idea' idea.module { @@ -193,13 +194,13 @@ task aggregateJavadocs(type: Javadoc) { options.addStringOption( 'Xdoclint:none', '-quiet' ) - if ( gradle.ext.javaToolchainEnabled ) { + if ( jdkVersions.explicit ) { options.setJFlags( getProperty( 'toolchain.javadoc.jvmargs' ).toString(). split( ' ' ).toList().findAll( { !it.isEmpty() } ) ) } } - if ( gradle.ext.javaToolchainEnabled ) { + if ( jdkVersions.explicit ) { // Display version of Java tools doFirst { if ( javadocTool.present ) { diff --git a/settings.gradle b/settings.gradle index 341ca25330..d853a4748f 100644 --- a/settings.gradle +++ b/settings.gradle @@ -51,6 +51,13 @@ dependencyResolutionManagement { } versionCatalogs { + jdks { + version( "baseline", "11" ) + + // Gradle does bytecode transformation on tests. + // You can't use bytecode higher than what Gradle supports, even with toolchains. + version( "maxSupportedBytecode", "21" ) + } libs { def antlrVersion = "4.10.1" def byteBuddyVersion = "1.14.7" @@ -278,79 +285,6 @@ buildCache { } } -gradle.ext.baselineJavaVersion = JavaLanguageVersion.of( 11 ) - -// Gradle does bytecode transformation on tests. -// You can't use bytecode higher than what Gradle supports, even with toolchains. -def GRADLE_MAX_SUPPORTED_BYTECODE_VERSION = 21 - -// If either 'main.jdk.version' or 'test.jdk.version' is set, enable the toolchain and use the selected jdk. -// If only one property is set, the other defaults to the baseline Java version (11). -// Note that when toolchain is enabled, you also need to specify -// the location of the selected jdks -// (auto-download and auto-detect are disabled in gradle.properties). -// -// Example (with SDKMAN): -// ./gradlew build -Ptest.jdk.version=15 \ -// -Porg.gradle.java.installations.paths=$SDKMAN_CANDIDATES_DIR/java/15.0.1-open,$SDKMAN_CANDIDATES_DIR/java/8 -if ( hasProperty( 'main.jdk.version' ) || hasProperty( 'test.jdk.version' ) ) { - // Testing a particular JDK version - // Gradle doesn't support all JDK versions unless we use toolchains - gradle.ext.javaToolchainEnabled = true - gradle.ext.javaVersions = [ - main: [ - compiler: JavaLanguageVersion.of( hasProperty( 'main.jdk.version' ) - ? getProperty( 'main.jdk.version' ) : gradle.ext.baselineJavaVersion.asInt() ), - release: gradle.ext.baselineJavaVersion - ], - test: [ - compiler: JavaLanguageVersion.of( hasProperty( 'test.jdk.version' ) - ? getProperty( 'test.jdk.version' ) : gradle.ext.baselineJavaVersion.asInt() ) - ] - ] - def testCompilerVersion = gradle.ext.javaVersions.test.compiler - if ( testCompilerVersion.asInt() > GRADLE_MAX_SUPPORTED_BYTECODE_VERSION ) { - logger.warn( "[WARN] Gradle does not support bytecode version '${testCompilerVersion}'." + - " Forcing test bytecode to version ${GRADLE_MAX_SUPPORTED_BYTECODE_VERSION}." ) - gradle.ext.javaVersions.test.release = JavaLanguageVersion.of( GRADLE_MAX_SUPPORTED_BYTECODE_VERSION ) - } - else { - gradle.ext.javaVersions.test.release = testCompilerVersion - } - gradle.ext.javaVersions.test.launcher = testCompilerVersion -} -else { - // Not testing a particular JDK version: we will use the same JDK used to run Gradle. - // We disable toolchains for convenience, so that anyone can just run the build with their own JDK - // without any additional options and without downloading the whole JDK. - gradle.ext.javaToolchainEnabled = false - def gradleJdkVersion = JavaLanguageVersion.of( JavaVersion.current().getMajorVersion() ) - if ( gradleJdkVersion.asInt() > GRADLE_MAX_SUPPORTED_BYTECODE_VERSION ) { - logger.warn( "[WARN] Gradle does not support this JDK, because it is too recent; build is likely to fail." + - " To avoid failures, you should use an older Java version when running Gradle, and rely on toolchains." + - " To that end, specify the version of Java you want to run tests with using property 'test.jdk.version'," + - " and specify the path to JDK8 *and* a JDK of the test version using property 'org.gradle.java.installations.paths'." + - " Example:" + - "./gradlew build -Ptest.jdk.version=15 -Porg.gradle.java.installations.paths=\$SDKMAN_CANDIDATES_DIR/java/15.0.1-open,\$SDKMAN_CANDIDATES_DIR/java/8" ) - } - - gradle.ext.javaVersions = [ - main: [ - compiler: gradleJdkVersion, - release: gradle.ext.baselineJavaVersion - ], - test: [ - compiler: gradleJdkVersion, - release: JavaLanguageVersion.of( - Math.min( GRADLE_MAX_SUPPORTED_BYTECODE_VERSION, gradleJdkVersion.asInt() ) ), - launcher: gradleJdkVersion - ] - ] -} - -logger.lifecycle "Java versions for main code: " + gradle.ext.javaVersions.main -logger.lifecycle "Java versions for tests: " + gradle.ext.javaVersions.test - include 'hibernate-core' include 'hibernate-testing' diff --git a/tooling/hibernate-gradle-plugin/hibernate-gradle-plugin.gradle b/tooling/hibernate-gradle-plugin/hibernate-gradle-plugin.gradle index ad1f68b700..a11901a7b3 100644 --- a/tooling/hibernate-gradle-plugin/hibernate-gradle-plugin.gradle +++ b/tooling/hibernate-gradle-plugin/hibernate-gradle-plugin.gradle @@ -15,6 +15,8 @@ plugins { // for local publishing id 'maven-publish' + + id 'org.hibernate.orm.build.jdks' } apply from: rootProject.file( 'gradle/module.gradle' ) @@ -125,10 +127,10 @@ tasks.withType( JavaCompile ) { options.encoding = 'UTF-8' } -if ( !gradle.ext.javaToolchainEnabled ) { +if ( !jdkVersions.explicit ) { tasks.withType( GroovyCompile ) { - sourceCompatibility = JavaVersion.toVersion( gradle.ext.baselineJavaVersion ) - targetCompatibility = JavaVersion.toVersion( gradle.ext.baselineJavaVersion ) + sourceCompatibility = JavaVersion.toVersion( gradle.jdkVersions.baseline ) + targetCompatibility = JavaVersion.toVersion( gradle.jdkVersions.baseline ) } } else { diff --git a/tooling/metamodel-generator/hibernate-jpamodelgen.gradle b/tooling/metamodel-generator/hibernate-jpamodelgen.gradle index 693ed3e6e9..a158ec3b44 100644 --- a/tooling/metamodel-generator/hibernate-jpamodelgen.gradle +++ b/tooling/metamodel-generator/hibernate-jpamodelgen.gradle @@ -44,12 +44,12 @@ compileTestJava { // Tests with records -if ( gradle.ext.javaVersions.test.release.asInt() >= 17 && gradle.ext.javaToolchainEnabled ) { +if ( jdkVersions.test.release.asInt() >= 17 && jdkVersions.explicit ) { // We need to configure the source and target version to 17 //compileTestJava17Java { compileTestJava { javaCompiler = javaToolchains.compilerFor { - languageVersion = gradle.ext.javaVersions.test.compiler + languageVersion = gradle.jdkVersions.test.compile } sourceCompatibility = 17 targetCompatibility = 17