Skip to content

feat(grails-gradle): move indy configuration from generated apps to Gradle plugin#15375

Merged
jamesfredley merged 4 commits into7.1.xfrom
feat/move-indy-config-to-gradle-plugin
Feb 19, 2026
Merged

feat(grails-gradle): move indy configuration from generated apps to Gradle plugin#15375
jamesfredley merged 4 commits into7.1.xfrom
feat/move-indy-config-to-gradle-plugin

Conversation

@jamesfredley
Copy link
Contributor

@jamesfredley jamesfredley commented Feb 3, 2026

Summary

Move the Groovy invokedynamic (indy) configuration from generated build.gradle files to the Grails Gradle Plugin, centralizing the setting and providing user feedback.

Changes

  • Add indy property to GrailsExtension (default: false)
  • Configure GroovyCompile tasks in GrailsGradlePlugin to use the extension's indy setting
  • Display lifecycle message explaining indy is disabled for performance and how to enable it
  • Remove hardcoded indy=false from grails-forge template
  • Remove hardcoded indy=false from grails-profiles base skeleton

User Experience

The message appears once per project during configuration:

> Configure project :
Grails: Groovy invokedynamic (indy) is disabled to improve performance (see issue #15293).
        To enable invokedynamic: grails { indy = true } in build.gradle

Users can enable indy in their build.gradle:

grails {
    indy = true
}

Testing

  • ✅ grails-gradle-plugins compiles successfully
  • ✅ grails-forge-core compiles successfully
  • ✅ Message appears once during project configuration
  • ✅ Application starts and runs correctly

Closes #15321

Documentation

  • Updated the upgrade guide (upgrading60x.adoc) to reflect that the Grails Gradle Plugin now handles indy configuration automatically
  • Users upgrading are instructed to remove the manual tasks.withType(GroovyCompile) block from their build.gradle
  • Documents the new grails { indy = true } extension for re-enabling invokedynamic

@jamesfredley jamesfredley moved this to In Progress in Apache Grails Feb 3, 2026
@jamesfredley jamesfredley added this to the grails:7.0.8 milestone Feb 3, 2026
@jamesfredley jamesfredley self-assigned this Feb 3, 2026
@jamesfredley jamesfredley force-pushed the feat/move-indy-config-to-gradle-plugin branch from 8dbb060 to f4a0ed7 Compare February 3, 2026 17:35
@jdaugherty jdaugherty requested a review from matrei February 3, 2026 17:48
@jdaugherty
Copy link
Contributor

#15321 was already closed by adding it to the gradle file.

Can you help me understand why you want to move this to the extension? The current implementation will break anyone who tries to override it - which is something significant enough that I think it should at least go into 7.1.x.

Are you wanting to change this default to true in Grails 8? That's the only reason I can think to move it to the extension.

* When enabled, Groovy uses JVM invokedynamic instead of traditional callsite caching.
* To enable invokedynamic in build.gradle: grails { indy = true }
*/
boolean indy = false
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For anyone that generated an application with the 7.0.6+ codeline, it will now flip it back to false - making this a breaking change.

@bito-code-review
Copy link

The change introduces a configurable 'indy' option in GrailsExtension, defaulting to false, and removes the hardcoded 'indy = false' from build templates. For apps generated with 7.0.6+ that had this setting, behavior remains the same. However, existing apps without the explicit setting may see indy flipped from its previous default (likely true) to false, potentially causing a breaking change in performance or behavior.

@jamesfredley
Copy link
Contributor Author

indy=false provides a massive performance improvement in Grails 7.x and I think we should consider making it the default without the extra config in build.gradle.

As we work on Grails 8 we may be able to achieve performance closer with some ideas from #15374 plus changes in Groovy.

…radle plugin

Move the Groovy invokedynamic (indy) configuration from generated
build.gradle files to the Grails Gradle Plugin, centralizing the
setting and providing user feedback.

Changes:
- Add 'indy' property to GrailsExtension (default: false)
- Configure GroovyCompile tasks in GrailsGradlePlugin to use the
  extension's indy setting
- Display lifecycle message explaining indy is disabled for
  performance and how to enable it
- Remove hardcoded indy=false from grails-forge template
- Remove hardcoded indy=false from grails-profiles base skeleton

The message appears once per project during configuration:
  Grails: Groovy invokedynamic (indy) is disabled to improve
          performance (see issue #15293).
          To enable invokedynamic: grails { indy = true } in build.gradle

Closes #15321
@jamesfredley jamesfredley force-pushed the feat/move-indy-config-to-gradle-plugin branch from f4a0ed7 to c9544f6 Compare February 3, 2026 18:14
@jamesfredley jamesfredley changed the base branch from 7.0.x to 7.1.x February 4, 2026 22:33
Copy link
Contributor

@jdaugherty jdaugherty left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm good with this going into 7.1, but we need to update the upgrade guide to point out this difference. Can you add a blurb about this change?

Users upgrading can now remove the manual tasks.withType(GroovyCompile)
block from build.gradle since the Grails Gradle Plugin handles this
automatically. Documents the new grails { indy = true } extension for
re-enabling invokedynamic.

Assisted-by: Claude Code <Claude@Claude.ai>
Copilot AI review requested due to automatic review settings February 19, 2026 13:38
@jamesfredley
Copy link
Contributor Author

Added an update to the upgrade guide (upgrading60x.adoc) that documents this change. It tells users they can remove the manual tasks.withType(GroovyCompile) block from their build.gradle and documents the new grails { indy = true } extension for re-enabling invokedynamic.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Centralizes Groovy invokedynamic (“indy”) configuration by moving it out of generated application build.gradle templates and into the Grails Gradle plugin, with an extension flag intended to let users opt back in.

Changes:

  • Adds indy to GrailsExtension (default false) and wires it into GroovyCompile task configuration.
  • Logs a lifecycle message when indy is disabled and explains how to enable it.
  • Removes the hardcoded indy = false blocks from forge/profile templates and updates the upgrade guide accordingly.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
grails-profiles/base/skeleton/build.gradle Removes template-level GroovyCompile indy disabling block.
grails-gradle/plugins/src/main/groovy/org/grails/gradle/plugin/core/GrailsGradlePlugin.groovy Configures GroovyCompile indy based on the Grails extension; adds a lifecycle message.
grails-gradle/plugins/src/main/groovy/org/grails/gradle/plugin/core/GrailsExtension.groovy Introduces indy as a Property<Boolean> with default false.
grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/build/gradle/templates/buildGradle.rocker.raw Removes template-level GroovyCompile indy disabling block.
grails-doc/src/en/guide/upgrading/upgrading60x.adoc Updates guidance to reflect plugin-managed indy and documents re-enabling it.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Add setIndy(boolean) to GrailsExtension so grails { indy = true } DSL
syntax works with the Property<Boolean> field. Move the GroovyCompile
indy configuration into afterEvaluate to ensure it reads the final
extension value after the user's build script has been evaluated.

Assisted-by: Claude Code <Claude@Claude.ai>
----

* By default, Groovy 4 switches away from callsite optimizations and uses invokedynamic instead. This can result in performance regressions compared to Grails 6. Groovy 5 will remove the ability to disable invokedynamic, but to disable it for Groovy 4, modify your `build.gradle` to include the following:
* By default, Groovy 4 switches away from callsite optimizations and uses invokedynamic instead. This can result in performance regressions compared to Grails 6. The Grails Gradle Plugin now automatically disables invokedynamic for all `GroovyCompile` tasks (see https://github.com/apache/grails-core/issues/15293[#15293]). If you have a manual `tasks.withType(GroovyCompile)` block in your `build.gradle` that sets `indy = false`, you can safely remove it:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would say "plugins" since applying any of them will cause it to disable.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very good point.

Copy link
Contributor

@jdaugherty jdaugherty left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor comment, otherwise good to merge.

@jamesfredley jamesfredley merged commit d1db8ab into 7.1.x Feb 19, 2026
24 of 25 checks passed
@jamesfredley jamesfredley deleted the feat/move-indy-config-to-gradle-plugin branch February 19, 2026 14:36
@github-project-automation github-project-automation bot moved this from In Progress to Done in Apache Grails Feb 19, 2026
@jdaugherty
Copy link
Contributor

@jamesfredley reviewing #15396 made me realize that we're not really testing both ways - with indy & without. This change will effectively make it so our apps only test with it off. Is this a good idea given that indy is more problematic?

jamesfredley added a commit to jamesfredley/grails-core that referenced this pull request Feb 19, 2026
Add indy: [false, true] matrix dimension to all functional test CI
jobs (functional, hibernate5, mongodb, forge) to ensure Groovy
invokedynamic is tested both enabled and disabled.

After PR apache#15375 moved indy configuration from generated build.gradle
files to the Grails Gradle Plugin, CI was only testing with the
default (indy=false). This leaves indy=true completely untested.

Changes:
- Add grailsIndy property toggle to grails-extension-gradle-config.gradle
  so test example projects respect -PgrailsIndy=true/false
- Add indy matrix to functional, hibernate5Functional, mongodbFunctional,
  and buildForge CI jobs
- Include indy status in job names for clear CI dashboard visibility

Assisted-by: Claude Code <Claude@Claude.ai>
@jamesfredley
Copy link
Contributor Author

@jdaugherty That's a big one: PR: #15415

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

Disable invoke dynamic by default

3 participants

Comments