codeconsole commented on code in PR #16292:
URL: https://github.com/apache/grails-core/pull/16292#discussion_r3961352856


##########
grails-doc/src/en/guide/plugins/hookingIntoRuntimeConfiguration.adoc:
##########
@@ -193,6 +204,30 @@ bean('greeting', Greeting) {
 }
 ----
 
+A third statement kind, `group(["name"]).<conditions> { ... }`, declares a 
nested static `@Configuration(proxyBeanMethods = false)` class holding the 
declarations in its body, with the chained conditions on the class rather than 
on each bean:
+
+[source,groovy]
+----
+group('imageServing').conditionalOnClass(name: 
'com.example.ManagedFileAccessProvider') {
+    bean('roomFileAccessProvider', RoomFileAccessProvider)
+    bean('chatFileAccessProvider', ChatFileAccessProvider)
+}
+----
+
+This is the shape real auto-configurations take — Spring Boot's own 
`JacksonAutoConfiguration` carries four nested `@ConditionalOnClass` 
configuration classes — and it is the only shape that works for a bean whose 
*own signature* names a class that may be absent. A condition is read from the 
bytecode before anything is loaded, but a `@Bean` method's parameter and return 
types are resolved when its configuration class is parsed, so guarding such a 
bean on the method is not reliably safe; moving it into a group moves the guard 
onto a class that is never parsed when the condition fails. Spring finds the 
nested class unaided, since `ConfigurationClassParser` processes a 
configuration class's member classes. Groups take the condition qualifiers and 
`.annotate(...)`; they do not nest, and the closure takes no parameters, since 
it declares a class rather than a bean.
+
+=== Diagnostics
+
+Three mistakes the DSL used to accept are now compile errors, because each of 
them fails at runtime in a way that is hard to trace back:
+
+* A `beans` closure containing any top-level `bean`/`field`/`method` call must 
be entirely such calls. A stray statement among real declarations — a typo in a 
call name, or an `if` wrapped around some beans — used to make the whole block 
register *nothing*, silently, with the failure surfacing far away as beans that 
are simply absent. To register a bean conditionally, put the condition on the 
bean rather than around it; for state or logic shared between beans, use 
`field(...)` or `method(...)`. A `beans` closure containing no such calls at 
all is not the DSL and is left alone, as before.
+* Calling one bean from another does not return the registered singleton 
unless the host is a proxied `@Configuration` class — and the DSL's usual hosts 
are not: `@AutoConfiguration` is `@Configuration(proxyBeanMethods = false)`, a 
generated plugin sibling carries exactly that, and an `Application` class is a 
configuration source without being annotated at all. Such a call silently 
constructs a second instance, so it is rejected; inject the bean as a closure 
parameter instead. A static `@Bean` method is never intercepted even on a 
proxied class, so `.staticMethod()` beans are checked everywhere.
+* A `BeanFactoryPostProcessor` or `BeanPostProcessor` bean must be 
`.staticMethod()`.
+
+=== Seeing what a block compiled to
+
+Building with `-Dgrails.beans.dsl.dumpdir=<dir>` writes one `<qualified 
name>.beans.txt` per host class, listing the generated members — bean names, 
the annotations the qualifiers became, modifiers, declared types with any type 
arguments they ended up carrying, and parameter annotations. Bodies are 
omitted, being the closure bodies from the source. Nothing is written unless 
the property is set.

Review Comment:
   Valid, and the feature was effectively documented into uselessness — fixed 
in 902f082.
   
   You are right about why I missed it: the spec sets the property with 
System.setProperty inside the test JVM, where compilation happens in-process, 
so it never exercised the documented invocation. The guide now shows
   
       tasks.withType(GroovyCompile).configureEach {
           groovyOptions.forkOptions.jvmArgs += 
"-Dgrails.beans.dsl.dumpdir=/absolute/path/to/beans"
       }
   
   and says why: GroovyCompile forks, so -D on the Gradle command line sets the 
property on the client and daemon rather than on the process that runs the 
transform. The absolute-path point is in there too, with the reason — a 
relative path resolves against that worker working directory, not the project 
one.



-- 
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