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]

Reply via email to