codeconsole opened a new pull request, #16398:
URL: https://github.com/apache/grails-core/pull/16398

   #16385 keeps precompiled scaffold pages in the controllers' view 
directories, so the build has to predict every precedence decision the runtime 
resolver makes: declared views, plugin views, namespaces, template overrides, 
controllers sharing a name. Each review round found another place that 
prediction drifted, and where it could not predict safely it gave up 
precompilation. Namespaced controllers, same-named controllers scaffolding 
different domains, and namespace-specific templates are all still expanded at 
runtime, which a native image cannot do.
   
   This moves the decision back to the runtime and precompiles only the 
expensive part.
   
   - **Build.** `generateScaffoldedViews` finds the scaffolded domain classes 
(ASM, as before) and the templates (application overrides, then the classpath 
in order, namespace-specific ones included). It then runs 
`org.apache.grails.scaffolding.ScaffoldedPagesGenerator` in a JVM on the 
application's runtime classpath, which expands each template for each domain 
class with the runtime's own `ModelBuilder`, `ScaffoldedPages` and Groovy, and 
writes it to `grails-scaffolded/<domain class>/<template path>-<digest>.gsp`. 
`compileGroovyPages` compiles it with the application's views. The digest 
covers the template and the model names the template mentions.
   - **Runtime.** `ScaffoldingViewResolver` chooses the template exactly as 
before. Where it used to expand and compile it, it computes the same name and 
serves the compiled page when there is one; otherwise it expands the template 
as before and warns once.
   
   Consequences:
   
   - A compiled page cannot shadow a declared view. `grails-scaffolded` cannot 
be a controller's view directory (it has a hyphen), and a page is used only for 
the exact template and model it was expanded from. The plugin view-index 
scanning, namespace detection and view-directory collision handling from #16385 
are no longer needed and are removed.
   - Namespaced controllers, same-named controllers scaffolding different 
domains, and namespace-specific and custom-named templates are all precompiled.
   - A template the build did not see (from a template-override plugin, or the 
legacy `static scaffold` property) is expanded at runtime, and the resolver 
warns once per template and domain class.
   - The build and the resolver share one implementation, so they cannot drift, 
and templates are read as UTF-8 in both. Model names a template does not 
mention are left out of the digest, so a page is still found when a value such 
as `packagePath` differs between the build machine and the runtime.
   - Native images: the templates are registered as resources, because the 
resolver reads a template to name its page. When the template a native image 
resolves has no compiled page, it is served the page compiled from another copy 
of the same template on the classpath, with a warning; the JVM expands instead. 
Checked against GraalVM 25 with a standalone probe: `getResource` returns the 
first copy in classpath order, as on the JVM, and `getResources` returns every 
copy.
   - `GroovyPageViewResolver.createGroovyPageView` is now protected. 
`ScaffoldingViewResolver.tryGenerateScaffoldedView` is now protected and takes 
the candidate template paths.
   
   Cost: once a view is resolved, a request costs one more view-cache key 
computation and map lookup than with #16385 (the parent resolver caches the 
null result for a scaffolded view). The first request for each view reads and 
hashes its template. The build forks one JVM when scaffolding inputs change; 
the task stays cacheable, with the generator classpath as an input.
   
   Validation:
   
   ```text
   ./gradlew :grails-scaffolding:test :grails-scaffolding:codeStyle 
:grails-web-gsp:test :grails-web-gsp:codeStyle 
:grails-test-examples-scaffolding:test
   cd grails-gradle
   ./gradlew :grails-gradle-plugins:test :grails-gradle-plugins:codeStyle 
:grails-gradle-plugins:validateDependencyVersions
   ```
   
   All pass (62, 19, 12 and 281 tests). `grails-test-examples-scaffolding:test` 
gains `PrecompiledScaffoldPagesSpec`, which runs the real resolver against the 
real templates and the pages the example's own build compiled. It checks that 
every view of a controller, a namespaced controller, and a same-named 
controller scaffolding a different domain is served from a compiled page, with 
nothing expanded at runtime.
   
   Not run, and **not claimed to pass**: the example's Geb integration tests, 
the repository-wide `aggregateViolations` check, and a native build of a full 
application. Resource precedence in a native image was checked only with the 
standalone probe.
   


-- 
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