You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
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
thrownewConfigurationException("Invalid value for setting [$propertyPathForArg]: $cause.message", cause)
587
+
} catch (Exception e2) {
588
+
thrownewConfigurationException("Invalid value for setting [$propertyPathForArg]: $e2.message", e2)
589
+
}
590
+
}
591
+
592
+
if (rawValue !=null) {
593
+
thrownewConfigurationException("Invalid value for setting [$propertyPathForArg]: cannot convert value [$rawValue] to required type [$argType.name]", e)
594
+
}
595
+
596
+
// If we have a fallback value, return it
597
+
if (fallBackValue !=null) {
598
+
return fallBackValue
599
+
}
600
+
601
+
if (e !=null) {
602
+
thrownewConfigurationException("Invalid value for setting [$propertyPathForArg]: $e.message", e)
0 commit comments