@org.codehaus.groovy.transform.GroovyASTTransformation(phase = CompilePhase.CANONICALIZATION) public class GrailsBeansASTTransformation extends java.lang.Object implements org.codehaus.groovy.transform.ASTTransformation, groovy.transform.CompilationUnitAware
Rewrites the beans closure DSL on a GrailsBeans-annotated
class into real @Bean factory methods, at compile time.
Recognises three kinds of top-level statement inside the beans closure:
bean(["name", ] Type) { ... }, optionally chained with any combination of
.conditionalOnMissingBean(...) (positional types, named annotation attributes, or bare),
.conditionalOnMissingBeanName(...) (backs off by this bean's own name, set
automatically), .primary(), .lazy(),
.scope("name"), .staticMethod() (a static factory method, for
BeanFactoryPostProcessor/BeanPostProcessor beans), and (repeatably)
.annotate(AnnotationType[, attr: value, ...]). Synthesises a public method, returning
the declared type, annotated @org.springframework.context.annotation.Bean("name") plus
whichever qualifiers were chained. Its parameters are always the DSL closure's own, annotations
included. Its body is the closure's, except where that body is empty - or the closure is omitted
altogether - in which case a new Type(...) call over those same parameters is synthesised
instead, leaving the compiler to select the constructor from their types exactly as it would for a
body written out by hand. The generated method's name is an implementation detail: it matches the
bean name when that is a usable Java identifier not already taken by an existing or generated
member, and falls back to a synthesized <type>$N name otherwise (a non-identifier name
like "my-service", a reserved keyword, or a collision - a bean named toString
never overrides Object.toString()) - Spring resolves the bean by its @Bean("name")
value either way, never by the method name. One bean name may be declared by several
bean(...) statements when every declaration carries its own discriminating condition
(see validateSharedBeanNames).field(["name", ] Type), optionally chained with .value(...) (config
injection: key + default, a bare key, or a verbatim placeholder/SpEL string) and/or (repeatably)
.annotate(AnnotationType[, attr: value, ...]). Declares a private field on the
generated class, for state shared across bean methods.method(["name", ] Type) { ... }, chainable with .annotate(...) only
(.value(...) is field-specific).
Declares a private helper method on the generated class, for logic shared across bean methods,
lifted from the DSL closure the same way bean(...) is.Fields and helper methods declared this way are ordinary private members of the generated
class - bean(...) closures reference them the same way a hand-written @Bean
method would reference a sibling field or method on its @Configuration class. The
beans property itself is removed so no closure survives into the compiled class.
When the annotated class extends grails.plugins.Plugin, the generated members land
on a new sibling class in the same package instead of on the plugin class itself - named by
swapping a *GrailsPlugin suffix for AutoConfiguration, or appending
AutoConfiguration otherwise. A Plugin subclass is instantiated by
DefaultGrailsPlugin via plain reflection, never as a Spring bean, so it cannot carry
@Bean methods or a meaningful @AutoConfiguration annotation of its own.
@AutoConfiguration and every annotation that gates or configures it - the
@Conditional* family, @Import/@ImportAutoConfiguration/
@ImportResource, @ComponentScan, @EnableConfigurationProperties,
@PropertySource/@PropertySources, and
@AutoConfigureOrder/Before/After - found on the plugin class are moved
onto the generated sibling, since that is the only place any of them has any effect; annotations
outside that set can be named explicitly via @GrailsBeans(moveAnnotations = ...). This lets a
plugin author keep bean definitions in the familiar *GrailsPlugin.groovy file while
everything else about the plugin class - doWithApplicationContext, onChange,
watchedResources, etc. - continues to work exactly as it does today.
@CompileStatic/@GrailsCompileStatic on the plugin class is propagated to the
generated sibling. Since the sibling is created after Groovy schedules local annotation
transforms, this transformation invokes Groovy's static-compilation transform directly after
generating the sibling's members. This is the same approach used by other Grails AST transforms
that generate code after local transform discovery.
| Type Params | Return Type | Name and description |
|---|---|---|
|
public void |
setCompilationUnit(org.codehaus.groovy.control.CompilationUnit compilationUnit) |
|
public void |
visit(org.codehaus.groovy.ast.ASTNode[] nodes, org.codehaus.groovy.control.SourceUnit source) |
| Methods inherited from class | Name |
|---|---|
class java.lang.Object |
java.lang.Object#equals(java.lang.Object), java.lang.Object#getClass(), java.lang.Object#hashCode(), java.lang.Object#notify(), java.lang.Object#notifyAll(), java.lang.Object#toString(), java.lang.Object#wait(), java.lang.Object#wait(long), java.lang.Object#wait(long, int) |