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]

Reply via email to