codeconsole commented on PR #16019:
URL: https://github.com/apache/grails-core/pull/16019#issuecomment-5066133755
The `grails-mail` conversion (6e4a52013d), same pattern. This one exercises
parameter-level annotations carrying through closure parameters —
`mailSender`'s optional session is declared `@Autowired(required = false)
@Qualifier('mailSession')` on the closure parameter, exactly as it was on the
original method — and wires `grails-beans-dsl` as `compileOnly`, matching this
module's provided-scope pattern for its Spring dependencies (the transform is
compile-time only; the retained `@GrailsBeans` annotation is inert when the jar
is absent). Imports and comments are trimmed here; each linked filename is the
verbatim, commit-pinned source.
Before,
[`MailAutoConfiguration.groovy`](https://github.com/codeconsole/grails-core/blob/53dcb874db7621286d37471412cab288990c9eef/grails-mail/src/main/groovy/grails/plugins/mail/MailAutoConfiguration.groovy#L36-L118)
(since deleted):
```groovy
@CompileStatic
@AutoConfiguration
@EnableConfigurationProperties(MailConfigurationProperties)
class MailAutoConfiguration {
@Bean
@ConditionalOnMissingBean
@ConditionalOnProperty(prefix = 'grails.mail', name = 'jndiName')
JndiObjectFactoryBean mailSession(MailConfigurationProperties
mailProperties) {
def factory = new JndiObjectFactoryBean()
factory.jndiName = mailProperties.jndiName
return factory
}
@Bean
@ConditionalOnMissingBean
JavaMailSender mailSender(
@Autowired(required = false)
@Qualifier('mailSession') Session mailSession,
MailConfigurationProperties mailProperties) {
def mailSender = new JavaMailSenderImpl()
if (mailProperties.host) {
mailSender.host = mailProperties.host
} else if (!mailProperties.jndiName) {
def envHost = System.getenv()['SMTP_HOST']
if (envHost) {
mailSender.host = envHost
} else {
mailSender.host = 'localhost'
}
}
if (mailProperties.encoding) {
mailSender.defaultEncoding = mailProperties.encoding
} else if (!mailProperties.jndiName) {
mailSender.defaultEncoding = 'utf-8'
}
if (mailSession != null) {
mailSender.session = mailSession
}
if (mailProperties.port) {
mailSender.port = mailProperties.port
}
if (mailProperties.username) {
mailSender.username = mailProperties.username
}
if (mailProperties.password) {
mailSender.password = mailProperties.password
}
if (mailProperties.protocol) {
mailSender.protocol = mailProperties.protocol
}
if (mailProperties.props) {
mailSender.javaMailProperties = mailProperties.props
}
return mailSender
}
@Bean
@ConditionalOnMissingBean
MailMessageBuilderFactory mailMessageBuilderFactory(
MailSender mailSender,
MailMessageContentRenderer mailMessageContentRenderer) {
new MailMessageBuilderFactory(mailSender, mailMessageContentRenderer)
}
@Bean
@ConditionalOnMissingBean
MailMessageContentRenderer mailMessageContentRenderer(
GroovyPagesTemplateEngine groovyPagesTemplateEngine,
GroovyPagesUriService groovyPagesUriService,
GrailsApplication grailsApplication,
GrailsPluginManager pluginManager) {
new MailMessageContentRenderer(groovyPagesTemplateEngine,
groovyPagesUriService, grailsApplication, pluginManager)
}
@Bean
@ConditionalOnMissingBean
MailService mailService(MailConfigurationProperties
mailConfigurationProperties,
MailMessageBuilderFactory
mailMessageBuilderFactory) {
new MailService(mailConfigurationProperties,
mailMessageBuilderFactory)
}
}
```
After —
[`MailGrailsPlugin.groovy`](https://github.com/codeconsole/grails-core/blob/6e4a52013d3103e1f8ccaffb363008da2cc26ec6/grails-mail/src/main/groovy/grails/plugins/mail/MailGrailsPlugin.groovy#L36-L139)'s
class declaration and `beans` block (the plugin's metadata properties between
them are elided below, unchanged by the conversion):
```groovy
@CompileStatic
@GrailsBeans
@AutoConfiguration
@EnableConfigurationProperties(MailConfigurationProperties)
class MailGrailsPlugin extends Plugin {
// ... pre-existing plugin metadata properties, unchanged ...
def beans = {
bean('mailSession',
JndiObjectFactoryBean).conditionalOnMissingBean().annotate(ConditionalOnProperty,
prefix: 'grails.mail', name: 'jndiName') { MailConfigurationProperties
mailProperties ->
def factory = new JndiObjectFactoryBean()
factory.jndiName = mailProperties.jndiName
return factory
}
bean('mailSender', JavaMailSender).conditionalOnMissingBean() {
@Autowired(required = false) @Qualifier('mailSession') Session mailSession,
MailConfigurationProperties mailProperties ->
def mailSender = new JavaMailSenderImpl()
if (mailProperties.host) {
mailSender.host = mailProperties.host
} else if (!mailProperties.jndiName) {
def envHost = System.getenv()['SMTP_HOST']
if (envHost) {
mailSender.host = envHost
} else {
mailSender.host = 'localhost'
}
}
if (mailProperties.encoding) {
mailSender.defaultEncoding = mailProperties.encoding
} else if (!mailProperties.jndiName) {
mailSender.defaultEncoding = 'utf-8'
}
if (mailSession != null) {
mailSender.session = mailSession
}
if (mailProperties.port) {
mailSender.port = mailProperties.port
}
if (mailProperties.username) {
mailSender.username = mailProperties.username
}
if (mailProperties.password) {
mailSender.password = mailProperties.password
}
if (mailProperties.protocol) {
mailSender.protocol = mailProperties.protocol
}
if (mailProperties.props) {
mailSender.javaMailProperties = mailProperties.props
}
return mailSender
}
bean(MailMessageBuilderFactory).conditionalOnMissingBean() {
MailSender mailSender, MailMessageContentRenderer mailMessageContentRenderer ->
new MailMessageBuilderFactory(mailSender,
mailMessageContentRenderer)
}
bean(MailMessageContentRenderer).conditionalOnMissingBean() {
GroovyPagesTemplateEngine groovyPagesTemplateEngine, GroovyPagesUriService
groovyPagesUriService, GrailsApplication grailsApplication, GrailsPluginManager
pluginManager ->
new MailMessageContentRenderer(groovyPagesTemplateEngine,
groovyPagesUriService, grailsApplication, pluginManager)
}
bean(MailService).conditionalOnMissingBean() {
MailConfigurationProperties mailConfigurationProperties,
MailMessageBuilderFactory mailMessageBuilderFactory ->
new MailService(mailConfigurationProperties,
mailMessageBuilderFactory)
}
}
```
The generated sibling regains the exact `MailAutoConfiguration` class
identity, so the `AutoConfiguration.imports` entry is untouched, and
`@EnableConfigurationProperties(MailConfigurationProperties)` moves onto it at
compile time. The plugin class is now `@CompileStatic`, preserving the deleted
class's static compilation — javap shows no `invokedynamic` call sites, and
`RuntimeVisibleParameterAnnotations` on the generated `mailSender` method's
`Session` parameter. The auto-configuration previously had no test coverage at
all; the new `MailAutoConfigurationSpec` asserts the defaulted and
property-driven mail sender configuration (the context starts with no
`mailSession` bean, proving the optional parameter), the `jndiName`-gated JNDI
session bean, user back-off, and the full mail service chain.
--
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]