codeconsole opened a new pull request, #15729:
URL: https://github.com/apache/grails-core/pull/15729
## Summary
Controller-side counterpart of #15717. `ScaffoldingControllerInjector` set
the injected superclass via `GrailsASTUtils.nonGeneric(superClassNode,
domainClass)`, so a scaffolded controller's superclass was written **raw** and
every inherited generic member erased to its `GormEntity` upper bound under
static compilation:
```groovy
@Scaffold(RestfulController<Widget>)
@GrailsCompileStatic
class WidgetController {
@Override
protected Widget queryForResource(Serializable id) {
def widget = super.queryForResource(id) // before: typed
GormEntity, not Widget
(widget?.owner == currentOwner) ? widget : null
}
}
```
fails with:
```
[Static type checking] - No such property: owner for class:
org.grails.datastore.gorm.GormEntity
[Static type checking] - Cannot return value of type
org.grails.datastore.gorm.GormEntity for method returning com.example.Widget
```
The common workaround in real apps is sprinkling `@CompileDynamic` over
every `queryForResource`/`createResource`/`listAllResources` override, giving
up static compilation exactly where project-scoping security checks live.
## Design
Same pattern #15717 applied to `ScaffoldingServiceInjector`: take a
`getPlainNodeReference()` copy of the resolved superclass, set its generics to
the domain type, mark the class node with `setUsingGenerics(true)` — injection
runs at CANONICALIZATION (after generics resolution), so the generic superclass
signature is only emitted when the class node itself reports `usesGenerics`;
otherwise it is written raw — then `setSuperClass(parameterizedSuper)`. Applies
to all three forms: `@Scaffold(Widget)`,
`@Scaffold(RestfulController<Widget>)`, and custom bases
`@Scaffold(ApiController<Widget>)` (the declared base is preserved, not
collapsed to `RestfulController`).
## Tests
New `ScaffoldingControllerInjectorSpec` mirroring
`ScaffoldingServiceInjectorSpec`:
- simple form `@Scaffold(Widget)` → `genericSuperclass` is
`RestfulController<Widget>`, not raw
- generic form `@Scaffold(RestfulController<Widget>)` → parameterized
- custom scaffold base preserved and parameterized as `CustomBase<Widget>`
- a `@CompileStatic` scaffolded controller overriding `queryForResource` /
`createResource` / `listAllResources` and narrowing the `super.*` results to
the domain type compiles without casts
All four tests fail against the previous injector and pass with the fix;
`:grails-scaffolding:test` passes in full.
--
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]