codeconsole opened a new pull request, #15759:
URL: https://github.com/apache/grails-core/pull/15759
### Summary
Adds an opt-in that compiles **every** controller and service with
`@GrailsCompileStatic` automatically, without annotating each class. Two
independent flags are exposed on the `grails` Gradle extension:
```groovy
grails {
compileStaticControllers = true // every grails-app/controllers class
compileStaticServices = true // every grails-app/services class
}
```
Both default to `false`. This automates what the framework's own guidance
already recommends doing per-class, while keeping it opt-in and reversible.
### Design
The configuration rides the same path PR #15118 established for the `grails
{ importJavaTime / starImports }` DSL, but the annotation is applied through an
artefact-aware AST injector rather than a global `ImportCustomizer`, because
static compilation is selective (controllers/services only), semantic (can fail
the build), and must yield to an explicit per-class choice — none of which a
blanket customizer can do.
- **Config + transport (grails-gradle):** `GrailsExtension` gains
`compileStaticControllers` / `compileStaticServices`. A new
`GrailsCompileStaticArtefactsProvider` (a `CommandLineArgumentProvider`,
modeled on the existing `GrailsAppBaseDirProvider`) publishes the enabled flags
to the Groovy compiler worker JVM as `-D` system properties. The property names
live in `grails.util.BuildSettings` alongside `APP_BASE_DIR`.
- **Application (grails-core):** `CompileStaticArtefactInjector` (an
`@AstTransformer` `GrailsArtefactClassInjector` for `Controller`/`Service`)
reads the `@Artefact` type, checks the corresponding flag, and applies
`@GrailsCompileStatic` via a new
`GrailsASTUtils.addGrailsCompileStaticAnnotation(ClassNode)` helper. That
helper reproduces `@GrailsCompileStatic` (i.e. `@CompileStatic` carrying the
Grails type-checking extensions) and registers the static-compile transform via
`ClassNode.addTransform`, the same mechanism the existing
`addCompileStaticAnnotation` uses so a late-added annotation still fires.
### Opt-out always wins
A class that declares its own `@CompileDynamic` (or `@GrailsCompileStatic` /
`@CompileStatic` / `@GrailsTypeChecked` / `@TypeChecked`) keeps that setting;
the opt-in never overrides an explicit choice:
```groovy
@CompileDynamic
class LegacyController {
// compiled dynamically even when grails.compileStaticControllers is
enabled
}
```
When both flags are unset (the default), the injector is fully inert.
### Tests
- `CompileStaticArtefactInjectorSpec` — controller/service compiled
statically when the flag is on (a type error fails compilation), dynamically
when off, and `@CompileDynamic` opted out even when on; services unaffected by
the controllers flag.
- `GrailsASTUtilsSpec` — `addGrailsCompileStaticAnnotation` applies
`@CompileStatic` with the full Grails extension list;
`hasStaticCompilationAnnotation` detects every opt-out annotation; the
extension list stays in sync with `@GrailsCompileStatic`.
- `GrailsCompileStaticArtefactsProviderSpec` + `GrailsExtensionSpec` — flags
default to false, are settable, and are published as the expected `-D` system
properties (read lazily).
Full `grails-core` suite (374 tests) and the `grails-gradle` plugins/model
suites pass; checkstyle + codenarc clean on the changed modules.
### Docs
Documented under the GrailsCompileStatic guide section and the Grails 8
"what's new" page (public DSL only).
--
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]