jamesfredley opened a new pull request, #15403:
URL: https://github.com/apache/grails-core/pull/15403
## Summary
GrailsGradlePlugin configures system properties and heap sizes for JavaExec
tasks but does not propagate the project's Java toolchain. Gradle's JavaPlugin
sets toolchain conventions on JavaCompile, Javadoc, and Test tasks but NOT on
JavaExec tasks. This means forked JVM processes (dbm-* migration tasks,
console, shell, application context commands) use the JDK running Gradle
instead of the project's configured toolchain.
## Bug Description
When a Grails project configures a Java toolchain:
```groovy
java {
toolchain {
languageVersion = JavaLanguageVersion.of(17)
}
}
```
JavaExec-based tasks (dbm-update, dbm-gorm-diff, console, shell,
urlMappingsReport) ignore the toolchain and use whichever JDK is running the
Gradle daemon. This causes `UnsupportedClassVersionError` when the project
targets a different JDK version.
## Root Cause
`GrailsGradlePlugin.configureForkSettings()` configures
`tasks.withType(JavaExec).configureEach()` with system properties and heap
sizes but does not set `javaLauncher`. Gradle's `JavaPlugin` only sets
toolchain conventions on `JavaCompile`, `Javadoc`, and `Test` tasks - NOT
`JavaExec`.
**Affected class**: `org.grails.gradle.plugin.core.GrailsGradlePlugin`
## Fix
Added `configureToolchainForForkTasks(Project project)` method that:
1. Checks if user explicitly configured `java.toolchain.languageVersion`
2. If yes, gets `JavaToolchainService` from project extensions
3. Creates a launcher via
`toolchainService.launcherFor(javaExtension.toolchain)`
4. Sets it as convention on ALL JavaExec tasks via
`task.javaLauncher.convention(launcher)`
Key design decisions:
- **Only targets JavaExec tasks** - Gradle already handles Test tasks
- **Uses `convention()` not `set()`** - allows per-task overrides
- **Guarded by `languageVersion?.isPresent()`** - zero behavior change for
users without toolchains
- **Uses `afterEvaluate`** - ensures toolchain config is fully resolved
## Test Coverage
8 JUnit Jupiter tests via Gradle TestKit (cannot use Spock due to Groovy 3/4
capability conflict in the plugins module):
**With toolchain configured:**
- JavaExec tasks inherit project toolchain
- Test tasks inherit project toolchain
- ApplicationContextCommandTask inherits toolchain (via grails-web plugin)
- convention() allows individual task override via set()
**Without toolchain (backwards compatibility):**
- JavaExec tasks work without errors when no toolchain configured
- GrailsWebGradlePlugin works without errors when no toolchain configured
**Fork settings preserved:**
- configureForkSettings applies system properties and default heap sizes
- Custom heap sizes are not overridden by fork settings
## Example Application
https://github.com/jamesfredley/grails-javaexec-toolchain-bug
## Environment Information
- Grails: 7.0.8-SNAPSHOT
- GORM: 7.0.8-SNAPSHOT
- Spring Boot: 3.5.10
- Groovy: 4.0.30 (app) / 3.0.25 (Gradle plugin compilation)
- JDK: 17 (Amazon Corretto 17.0.18)
- Gradle: 8.14.4
## Version
7.0.x
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]