|
|
|
/**
|
|
|
|
* Apply the JVM Toolchain conventions
|
|
|
|
* See https://docs.gradle.org/current/userguide/toolchains.html
|
|
|
|
*
|
|
|
|
* One can choose the toolchain to use for compiling the MAIN sources and/or compiling
|
|
|
|
* and running the TEST sources. These options apply to Java, Kotlin and Groovy sources
|
|
|
|
* when available.
|
|
|
|
* {@code "./gradlew check -PmainToolchain=17 -PtestToolchain=20"} will use:
|
|
|
|
* <ul>
|
|
|
|
* <li>a JDK17 toolchain for compiling the main SourceSet
|
|
|
|
* <li>a JDK20 toolchain for compiling and running the test SourceSet
|
|
|
|
* </ul>
|
|
|
|
*
|
|
|
|
* By default, the build will fall back to using the current JDK and 17 language level for all sourceSets.
|
|
|
|
*
|
|
|
|
* Gradle will automatically detect JDK distributions in well-known locations.
|
|
|
|
* The following command will list the detected JDKs on the host.
|
|
|
|
* {@code
|
|
|
|
* $ ./gradlew -q javaToolchains
|
|
|
|
* }
|
|
|
|
*
|
|
|
|
* We can also configure ENV variables and let Gradle know about them:
|
|
|
|
* {@code
|
|
|
|
* $ echo JDK17
|
|
|
|
* /opt/openjdk/java17
|
|
|
|
* $ echo JDK20
|
|
|
|
* /opt/openjdk/java20
|
|
|
|
* $ ./gradlew -Porg.gradle.java.installations.fromEnv=JDK17,JDK20 check
|
|
|
|
* }
|
|
|
|
*
|
|
|
|
* @author Brian Clozel
|
|
|
|
* @author Sam Brannen
|
|
|
|
*/
|
|
|
|
|
|
|
|
def mainToolchainConfigured() {
|
|
|
|
return project.hasProperty('mainToolchain') && project.mainToolchain
|
|
|
|
}
|
|
|
|
|
|
|
|
def testToolchainConfigured() {
|
|
|
|
return project.hasProperty('testToolchain') && project.testToolchain
|
|
|
|
}
|
|
|
|
|
|
|
|
def mainToolchainLanguageVersion() {
|
|
|
|
if (mainToolchainConfigured()) {
|
|
|
|
return JavaLanguageVersion.of(project.mainToolchain.toString())
|
|
|
|
}
|
|
|
|
return JavaLanguageVersion.of(17)
|
|
|
|
}
|
|
|
|
|
|
|
|
def testToolchainLanguageVersion() {
|
|
|
|
if (testToolchainConfigured()) {
|
|
|
|
return JavaLanguageVersion.of(project.testToolchain.toString())
|
|
|
|
}
|
|
|
|
return mainToolchainLanguageVersion()
|
|
|
|
}
|
|
|
|
|
|
|
|
plugins.withType(JavaPlugin) {
|
|
|
|
// Configure the Java Toolchain if the 'mainToolchain' is configured
|
|
|
|
if (mainToolchainConfigured()) {
|
|
|
|
java {
|
|
|
|
toolchain {
|
|
|
|
languageVersion = mainToolchainLanguageVersion()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// Fallback to JDK17
|
|
|
|
java {
|
|
|
|
sourceCompatibility = JavaVersion.VERSION_17
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Configure a specific Java Toolchain for compiling and running tests if the 'testToolchain' property is defined
|
|
|
|
if (testToolchainConfigured()) {
|
|
|
|
def testLanguageVersion = testToolchainLanguageVersion()
|
|
|
|
tasks.withType(JavaCompile).matching { it.name.contains("Test") }.configureEach {
|
|
|
|
javaCompiler = javaToolchains.compilerFor {
|
|
|
|
languageVersion = testLanguageVersion
|
|
|
|
}
|
|
|
|
}
|
|
|
|
tasks.withType(Test).configureEach{
|
|
|
|
javaLauncher = javaToolchains.launcherFor {
|
|
|
|
languageVersion = testLanguageVersion
|
|
|
|
}
|
Allow JDK 20 builds to pass by using legacy locale data
After setting up a JDK 20 CI build pipeline, numerous tests involving
date/time parsing and formatting began to fail [0]. (The failing JPA
tests are not specific to JDK 20.)
For example, we encounter visually confusing assertion failures such as
the following.
org.opentest4j.AssertionFailedError:
expected: "12:00 PM"
but was: "12:00 PM"
The expected string contains a normal space (which has always been the
case prior to JDK 20); whereas, the actual string now contains a narrow
non-breaking space.
The cause of this is mentioned in the JDK 20 Release Notes [1] as "NBSP
prefixed to a, instead of a normal space". Note, however, that the
links for the first two bullet points in that section are mixed up.
"NBSP prefixed to a, instead of a normal space" should point to [2].
Furthermore, the new whitespace character is not a non-breaking space
(NBSP) but rather a narrow non-breaking space (NNBSP). In addition, the
second bullet point should technically read "NNBSP prefixed to `a`,
instead of a normal space" -- even though `a` provides limited value to
most readers.
The downside for the Java community is that this constitutes a breaking
change for parsing and formatting date/time values that include "AM"
and "PM" units (any may potentially apply to other date/time
parsing/formatting scenarios). In Spring Framework's test suite we have
witnessed this in conjunction with Spring's @DateTimeFormat and
DateTimeFormatterFactory infrastructure as well as with Google's
Gson-to-JSON support.
A colleague who works at Oracle graciously informed me that one can use
"legacy locale data" by supplying `-Djava.locale.providers=COMPAT` as a
JVM argument, noting however that this option limits some newer
functionalities (but without enumerating which new functionalities one
might be missing when using this option).
In any case, this commit adds that JVM argument to our Gradle toolchain
builds so that our test suite passes on JDK 20, and we will continue to
investigate further options for our builds and for our users.
Note, however, that one must manually configure the
`-Djava.locale.providers=COMPAT` JVM argument when running affected
tests within an IDE.
See gh-30185
[0] https://ge.spring.io/s/kmiq2bz2afafs/tests/overview?outcome=failed
[1] https://jdk.java.net/20/release-notes#JDK-8284840
[2] https://unicode-org.atlassian.net/browse/CLDR-14032
2 years ago
|
|
|
jvmArgs += ['-Djava.locale.providers=COMPAT']
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
plugins.withType(GroovyPlugin) {
|
|
|
|
// Fallback to JDK17
|
|
|
|
if (!mainToolchainConfigured()) {
|
|
|
|
compileGroovy {
|
|
|
|
sourceCompatibility = JavaVersion.VERSION_17
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pluginManager.withPlugin("kotlin") {
|
|
|
|
// Fallback to JDK17
|
|
|
|
compileKotlin {
|
|
|
|
kotlinOptions {
|
|
|
|
jvmTarget = '17'
|
|
|
|
}
|
|
|
|
}
|
|
|
|
compileTestKotlin {
|
|
|
|
kotlinOptions {
|
|
|
|
jvmTarget = '17'
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Configure the JMH plugin to use the toolchain for generating and running JMH bytecode
|
|
|
|
pluginManager.withPlugin("me.champeau.jmh") {
|
|
|
|
if (mainToolchainConfigured() || testToolchainConfigured()) {
|
|
|
|
tasks.matching { it.name.contains('jmh') && it.hasProperty('javaLauncher') }.configureEach {
|
|
|
|
javaLauncher.set(javaToolchains.launcherFor {
|
|
|
|
languageVersion.set(testToolchainLanguageVersion())
|
|
|
|
})
|
|
|
|
}
|
|
|
|
tasks.withType(JavaCompile).matching { it.name.contains("Jmh") }.configureEach {
|
|
|
|
javaCompiler = javaToolchains.compilerFor {
|
|
|
|
languageVersion = testToolchainLanguageVersion()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Store resolved Toolchain JVM information as custom values in the build scan.
|
|
|
|
rootProject.ext {
|
|
|
|
resolvedMainToolchain = false
|
|
|
|
resolvedTestToolchain = false
|
|
|
|
}
|
|
|
|
gradle.taskGraph.afterTask { Task task, TaskState state ->
|
|
|
|
if (mainToolchainConfigured() && !resolvedMainToolchain && task instanceof JavaCompile && task.javaCompiler.isPresent()) {
|
|
|
|
def metadata = task.javaCompiler.get().metadata
|
|
|
|
task.project.buildScan.value('Main toolchain', "$metadata.vendor $metadata.languageVersion ($metadata.installationPath)")
|
|
|
|
resolvedMainToolchain = true
|
|
|
|
}
|
|
|
|
if (testToolchainConfigured() && !resolvedTestToolchain && task instanceof Test && task.javaLauncher.isPresent()) {
|
|
|
|
def metadata = task.javaLauncher.get().metadata
|
|
|
|
task.project.buildScan.value('Test toolchain', "$metadata.vendor $metadata.languageVersion ($metadata.installationPath)")
|
|
|
|
resolvedTestToolchain = true
|
|
|
|
}
|
|
|
|
}
|