codeconsole commented on PR #16019: URL: https://github.com/apache/grails-core/pull/16019#issuecomment-5066126555
The `grails-sitemesh3` conversion (53dcb874db) follows the same pattern, and drove one more DSL capability: `.staticMethod()` (5450dffcfe), which generates a `static` `@Bean` factory method — required for the two view-resolver post-processor beans, since a `BeanFactoryPostProcessor`/`BeanPostProcessor` bean must be creatable without instantiating its declaring configuration class. Imports and comments are trimmed here; each linked filename is the verbatim, commit-pinned source. Before, [`Sitemesh3AutoConfiguration.groovy`](https://github.com/codeconsole/grails-core/blob/5450dffcfe6bcc1c38ee30b8102f5492f976a4bc/grails-gsp/grails-sitemesh3/src/main/groovy/org/grails/plugins/sitemesh3/Sitemesh3AutoConfiguration.groovy#L19-L131) (since deleted): ```groovy @CompileStatic @AutoConfiguration @AutoConfigureAfter(name = 'org.springframework.boot.webmvc.autoconfigure.DispatcherServletAutoConfiguration') @AutoConfigureBefore(name = 'org.sitemesh.autoconfigure.SiteMeshViewResolverAutoConfiguration') @ConditionalOnClass(SiteMeshViewResolverBeanPostProcessor) @ConditionalOnProperty(name = 'sitemesh.integration', havingValue = 'view-resolver', matchIfMissing = true) class Sitemesh3AutoConfiguration { @Bean @ConditionalOnMissingBean(SiteMeshViewResolverPostProcessor) static Sitemesh3ViewResolverDefinitionPostProcessor siteMeshViewResolverPostProcessor() { new Sitemesh3ViewResolverDefinitionPostProcessor() } @Bean @ConditionalOnMissingBean(SiteMeshViewResolverBeanPostProcessor) static GrailsSiteMeshViewResolverBeanPostProcessor siteMeshViewResolverBeanPostProcessor() { new GrailsSiteMeshViewResolverBeanPostProcessor() } @Bean @ConditionalOnBean(DispatcherServlet) @ConditionalOnMissingBean(name = 'contentProcessor') CaptureAwareContentProcessor contentProcessor() { new CaptureAwareContentProcessor() } @Bean @ConditionalOnBean(DispatcherServlet) @ConditionalOnMissingBean(name = 'decoratorSelector') Sitemesh3LayoutFinder decoratorSelector(ObjectProvider<GrailsConventionGroovyPageLocator> groovyPageLocator, GrailsApplication grailsApplication) { Config config = grailsApplication.config Environment env = Environment.current boolean developmentMode = Metadata.current.isDevelopmentEnvironmentAvailable() boolean reloadEnabled = env.isReloadEnabled() || config.getProperty('grails.gsp.enable.reload', Boolean, false) || (developmentMode && env == Environment.DEVELOPMENT) String defaultLayout = config.getProperty('grails.sitemesh.default.layout') ?: config.getProperty('grails.views.layout.default') Sitemesh3LayoutFinder finder = new Sitemesh3LayoutFinder(groovyPageLocator.getIfAvailable()) finder.gspReloadEnabled = reloadEnabled finder.defaultDecoratorName = defaultLayout ?: null finder.layoutCacheExpirationMillis = config.getProperty('grails.sitemesh.layout.cache.interval', Long, 5000L) return finder } } ``` After — [`Sitemesh3GrailsPlugin.groovy`](https://github.com/codeconsole/grails-core/blob/53dcb874db7621286d37471412cab288990c9eef/grails-gsp/grails-sitemesh3/src/main/groovy/org/grails/plugins/sitemesh3/Sitemesh3GrailsPlugin.groovy#L19-L162)'s class declaration and `beans` block (the rest of the file — `beanRegistrar()`, the plugin metadata it already had — is untouched; the design documentation from the deleted class's javadoc moved onto the plugin): ```groovy @CompileStatic @GrailsBeans @AutoConfiguration @AutoConfigureAfter(name = 'org.springframework.boot.webmvc.autoconfigure.DispatcherServletAutoConfiguration') @AutoConfigureBefore(name = 'org.sitemesh.autoconfigure.SiteMeshViewResolverAutoConfiguration') @ConditionalOnClass(SiteMeshViewResolverBeanPostProcessor) @ConditionalOnProperty(name = 'sitemesh.integration', havingValue = 'view-resolver', matchIfMissing = true) class Sitemesh3GrailsPlugin extends Plugin { def grailsVersion = '7.0.0-SNAPSHOT > *' def title = 'SiteMesh 3' def author = 'Scott Murphy' def authorEmail = '' def description = 'Provides GSP layout decoration using SiteMesh 3' def profiles = ['web'] def license = 'APACHE' def developers = [[name: 'Scott Murphy']] def loadBefore = ['groovyPages'] def providedArtefacts = [ RenderSitemeshTagLib, Sitemesh3LayoutTagLib, ] def beans = { bean('siteMeshViewResolverPostProcessor', Sitemesh3ViewResolverDefinitionPostProcessor).staticMethod().conditionalOnMissingBean(SiteMeshViewResolverPostProcessor) { new Sitemesh3ViewResolverDefinitionPostProcessor() } bean('siteMeshViewResolverBeanPostProcessor', GrailsSiteMeshViewResolverBeanPostProcessor).staticMethod().conditionalOnMissingBean(SiteMeshViewResolverBeanPostProcessor) { new GrailsSiteMeshViewResolverBeanPostProcessor() } bean('contentProcessor', CaptureAwareContentProcessor).annotate(ConditionalOnBean, value: DispatcherServlet).conditionalOnMissingBeanName() { new CaptureAwareContentProcessor() } bean('decoratorSelector', Sitemesh3LayoutFinder).annotate(ConditionalOnBean, value: DispatcherServlet).conditionalOnMissingBeanName() { ObjectProvider<GrailsConventionGroovyPageLocator> groovyPageLocator, GrailsApplication grailsApplication -> Config config = grailsApplication.config grails.util.Environment env = grails.util.Environment.current boolean developmentMode = Metadata.current.isDevelopmentEnvironmentAvailable() boolean reloadEnabled = env.isReloadEnabled() || config.getProperty('grails.gsp.enable.reload', Boolean, false) || (developmentMode && env == grails.util.Environment.DEVELOPMENT) String defaultLayout = config.getProperty('grails.sitemesh.default.layout') ?: config.getProperty('grails.views.layout.default') Sitemesh3LayoutFinder finder = new Sitemesh3LayoutFinder(groovyPageLocator.getIfAvailable()) finder.gspReloadEnabled = reloadEnabled finder.defaultDecoratorName = defaultLayout ?: null finder.layoutCacheExpirationMillis = config.getProperty('grails.sitemesh.layout.cache.interval', Long, 5000L) return finder } } ``` The generated sibling regains the exact `Sitemesh3AutoConfiguration` class identity, so the module's `AutoConfiguration.imports` entry is untouched, and the class-level ordering and gating annotations (`@AutoConfigureAfter`/`Before` by name, `@ConditionalOnClass`, `@ConditionalOnProperty`) move onto it at compile time. The pre-existing `Sitemesh3AutoConfigurationSpec` passes unmodified — including its direct static invocations of the two post-processor factory methods — and javap confirms both methods are `static` and the class is fully statically compiled. The `grails-mail` conversion (6e4a52013d) is on the branch as well, exercising parameter-level `@Autowired(required = false)`/`@Qualifier` annotations carrying through closure parameters. -- 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]
