codeconsole opened a new pull request, #16407: URL: https://github.com/apache/grails-core/pull/16407
Follow-up to #16398. `generateScaffoldedViews` reads scaffolded controllers from every plugin on the **runtime** classpath, but `compileGroovyPages` compiles the pages it expands against a classpath built from the **compile** classpath. A plugin that reaches a project only at runtime is on the first and not the second. The usual way that happens is an `implementation` dependency of a project this one depends on. Every page expanded for such a plugin's controllers names a domain class the page compiler cannot resolve, so the compiler leaves each one out with a warning and the compiler error (names changed): ```text Left out the optional page grails-scaffolded/com.example.images.ManagedFile/index-78a2d25e9f37d1c1.gsp, which does not compile; if it is rendered it is produced then instead, and fails the same way: startup failed: gsp_reports_grails_scaffolded_com_example_images_ManagedFileindex_78a2d25e9f37d1c1_gsp.groovy: 13: unable to resolve class com.example.images.ManagedFile ``` Found in an application whose plugins depend on one another. A plugin that uses another plugin's services through an `implementation` dependency got the other plugin's scaffolded controllers on its runtime classpath. It then expanded and failed to compile four pages for each of them. That repeats in every project the plugin reaches, while the plugin's own build, which does have the domain classes, expands and compiles the same pages anyway. No page is lost by skipping them; the only effect was the warnings. - `GenerateScaffoldedViewsTask` gains `pageClasspath`: the classpath the pages are compiled against (`@CompileClasspath`). A plugin's controller has its pages expanded only where the domain class it scaffolds is on it. A controller left out is noted at INFO, naming the controller and the domain class. - `GroovyPagePlugin` wires `pageClasspath` from the same `FileCollection` it gives `compileGroovyPages`, so the check and the compilation cannot disagree. The consequence is that `generateScaffoldedViews` now also waits for `packageTagLibraryIndex`, which is part of that collection. - The class loader for the check has no parent, but a `URLClassLoader` with a `null` parent still delegates to the bootstrap loader. So a domain type the platform provides, such as `java.lang.Long`, resolves without an entry. - An application's own controllers are not checked. They were compiled against their domain classes, so those classes are on the compile classpath by construction. - The scaffolding guide says which plugins are covered. For a native image, the fix for a plugin an application has only at runtime is to declare it as a dependency of the application. Why this rather than compiling the pages against the runtime classpath: the generated pages and the application's views share one compilation (and one `gsp/views.properties`). Adding the runtime classpath there would also change what hand-written views compile against, and which plugins' tag libraries they resolve statically. A task registered by hand without `pageClasspath` expands pages for the application's own controllers as before. Only plugin controllers whose domain class is not a platform type are affected, and those are left out at INFO. Validation, from `grails-gradle/`: ```text ./gradlew :grails-gradle-plugins:test --tests 'org.grails.gradle.plugin.scaffolding.*' --tests 'org.grails.gradle.plugin.views.gsp.*' ./gradlew :grails-gradle-plugins:codeStyle ``` All pass: 78 tests across `GenerateScaffoldedViewsTaskSpec` (34), `GroovyPagePluginFunctionalSpec` (10), `TagLibraryIndexWiringFunctionalSpec` (7, which includes the no-dependency-cycle and configuration-cache wiring checks), `GenerateTagLibraryIndexTaskSpec` (15), `TagLibraryIndexFilesSpec` (7) and `GroovyPageToolchainSpec` (5). Coverage added: - `GroovyPagePluginFunctionalSpec`: a TestKit build with one plugin as an `implementation` dependency and one as `runtimeOnly`, each carrying its domain class. The first has its pages generated and handed to the compiler. The second has none, and the INFO note names it. - `GenerateScaffoldedViewsTaskSpec`: a plugin whose domain class is not on `pageClasspath` is left out while the others are expanded. A platform-provided domain type, and a plugin controller scaffolding a domain class of the project's own, are still expanded. The two existing plugin tests now put the plugin on `pageClasspath`, as an `implementation` dependency would. With the main-source change reverted, the new functional test and the new left-out unit test both fail. The two updated plugin tests fail too, because the property does not exist without the change. Not run, and **not claimed to pass**: the full `grails-gradle-plugins` test suite and the repository-wide `aggregateViolations` check. -- 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]
