The GitHub Actions job "Coverage" on grails-core.git/fix/spring7-nested-map-conversion has succeeded. Run started by GitHub user jamesfredley (triggered by jamesfredley).
Head commit for run: 5c99b411ff95ba5faf4afcfe4e9f5f40509f75d1 / James Fredley <[email protected]> fix(config): bind nested settings maps under Spring 7 Spring Framework 7 no longer converts a configuration Map into a type annotated @Builder(builderStrategy = SimpleStrategy), so nested settings failed to bind with ConverterNotFoundException. ConfigurationBuilder now instantiates the target type and populates it from the Map. The gap is demonstrable on this branch: with the previous ConfigurationBuilder and only the new spec applied, six scenarios fail with "Expected exception of type 'ConfigurationException', but got 'ConverterNotFoundException'". 9.0.x resolves spring-core 7.0.8 via Spring Boot 4.1.0. The fallback is deliberately narrow, and every guard below exists because removing it produced an observable failure: - It engages only when the cause chain contains ConverterNotFoundException, so a converter that deliberately rejects a Map is not bypassed. - ConfigurationException is never suppressed, so unknown-key and malformed-value failures still surface instead of being masked by the original conversion exception. - A failure while resolving the raw value throws rather than silently falling back, so configuration whose lookup failed is not quietly accepted. - The instance inherits from the fallback before overrides are applied, and each nested level receives its own fallback child, so overriding one field does not discard the rest. - Values are converted to the target property type, including the case-insensitive enum path, so multiTenancy.mode: database still binds. - Class-typed entries resolve through the thread context class loader, the same route the top-level Class handling uses, because the resolver's converter resolves against the framework class loader and would leave an application class such as hibernate.configClass unbound. - Types that are themselves a Map keep arbitrary entries. HibernateSettings extends LinkedHashMap precisely to carry keys like hibernate.hbm2ddl.auto, which strict property-only binding would have rejected. - Flattened descendant keys are bound once through their parent rather than rejected, since the resolver flattens nested configuration; a dotted key whose first segment is unknown is still rejected. - Setters are invoked with an explicit single-element argument array so an explicit null clears an inherited value. ConfigurationBuilderSpec grows from 10 to 22 specs covering each of the above. Known limitation: a PropertyResolver that exposes only an aggregate map, and not its entries as dotted properties, can still yield null for a configured scalar. Grails' own DatastoreUtils.createPropertyResolver flattens and is unaffected. Binding the raw value unconditionally was rejected as a fix because it would bypass the type conversion above. Assisted-by: claude-code:claude-opus-5 Report URL: https://github.com/apache/grails-core/actions/runs/31970380177 With regards, GitHub Actions via GitBox
