jamesfredley opened a new issue, #16159:
URL: https://github.com/apache/grails-core/issues/16159

   `ConfigurationBuilder` gained a Spring 7 compatibility path: when Spring 
cannot convert a configuration `Map` into a type annotated 
`@Builder(builderStrategy = SimpleStrategy)`, the builder instantiates the 
target and populates it from the Map. That path currently ships on the Groovy 6 
canary branch (#15558), where it is 261 of that branch's insertions despite its 
own docstring stating it is *"independent of the Groovy version"*.
   
   An attempt to extract it onto `9.0.x`, where it belongs, ran it through two 
independent code reviewers over four rounds. The gap on trunk is real - with 
trunk's original `ConfigurationBuilder` and only the new spec applied, six 
scenarios fail with:
   
   ```
   Expected exception of type 'ConfigurationException',
     but got 'org.springframework.core.convert.ConverterNotFoundException'
   ```
   
   `9.0.x` resolves `org.springframework:spring-core:7.0.8` via Spring Boot 
4.1.0, so the affected Spring version is present.
   
   However, the review surfaced nine distinct defects in the implementation. 
Seven were fixed and covered with tests; two remain open and need someone with 
Hibernate configuration-binding knowledge.
   
   ## Fixed, with regression tests
   
   | # | Defect | Consequence |
   |---|---|---|
   | 1 | Every non-enum `ConversionFailedException` triggered the Map fallback 
without checking the cause chain contained `ConverterNotFoundException` | A 
converter that deliberately rejects a Map could be bypassed |
   | 2 | A surrounding `catch (Throwable)` swallowed `ConfigurationException` | 
Unknown-key and malformed-value failures were masked by the original exception |
   | 3 | Raw-value resolution failures were logged and discarded, leaving the 
population-failure flag null | A non-null fallback was returned, silently 
accepting configuration whose lookup had failed |
   | 4 | Population built a fresh instance without copying the fallback | Every 
field the caller did not specify was lost, breaking `buildRecurse` per-field 
inheritance for named connection settings |
   | 5 | Map entries were assigned raw | Converters and case-insensitive enum 
handling were bypassed, so `multiTenancy.mode: database` was rejected where 
`DATABASE` worked |
   | 6 | Any key that was not a declared bean property was rejected | 
`HibernateSettings extends LinkedHashMap<String, String>` exists to carry 
arbitrary keys, so `hibernate.hbm2ddl.auto` would be rejected as an unknown 
setting |
   | 7 | `Method.invoke(instance, value)` hit the Java null-varargs pitfall | 
An explicit null could not clear an inherited value |
   
   Coverage went from 10 to 19 specs in `ConfigurationBuilderSpec`, module 
total 108 to 117, all passing on Groovy 5.
   
   ## Open, not fixed
   
   **A. Flattened descendant keys are rejected.** 
`DatastoreUtils.createPropertyResolver` flattens nested configuration, so a 
parent map contains both immediate children and flattened descendants - 
`hibernate.jpa` holds both `compliance` and `compliance.cascade`. Since 
`JpaSettings` is not map-backed, the flattened key reaches the strict 
unknown-key branch and is rejected, so configuration nested more than one level 
deep fails to build.
   
   **B. Fallback inheritance does not recurse.** When a fallback object has a 
nested child and the configuration overrides only part of that child, the 
nested resolve runs with a null fallback. The previously copied child is 
replaced, silently losing its unspecified fallback fields. Inheritance 
therefore works only at the first manually populated level.
   
   Both need validation against real Hibernate and multi-datasource 
configuration rather than unit-level mocks, which is why they are being 
reported rather than patched speculatively.
   
   ## Why this matters now
   
   Defects 1-7 and both open items are **live on the canary branch today**, 
since that is where this code currently resides. Items A and B in particular 
can reject valid configuration or silently reset inherited settings at 
application startup.
   
   ## Suggested handling
   
   1. Fix A and B with integration coverage over genuinely nested Hibernate 
configuration.
   2. Land the whole thing on `9.0.x` as a Spring 7 compatibility fix.
   3. Drop it from #15558, which then carries only genuine Groovy 6 workarounds 
and roughly halves in size.
   
   The seven fixes plus the 9 added specs exist on the local branch 
`fix/spring7-nested-map-conversion` and can be pushed if wanted as a starting 
point.
   


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