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]

Reply via email to