Configuring a Map property with an empty collection is no longer possible in 4.1.0, was working in 4.0.6.
Instead of the application starting with an empty map for that property, the startup fails with an Failed to load ApplicationContext error caused by:
Caused by: org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type [java.lang.String] to type [java.util.Map<java.lang.String, java.lang.String>]
e.g. with the following config class:
@ConfigurationProperties(prefix = "test")
public class TestProperties {
private Map<String, String> testmap = new HashMap<>();
public Map<String, String> getTestmap() {
return testmap;
}
public void setTestmap(final Map<String, String> testmap) {
this.testmap = testmap;
}
}
java.lang.IllegalStateException: Failed to load ApplicationContext for [WebMergedContextConfiguration@629fc74d testClass = **redacted**, locations = [], classes = [**redacted**, TestConfiguration], contextInitializerClasses = [], activeProfiles = [], propertySourceDescriptors = [], propertySourceProperties = ["org.springframework.boot.test.context.SpringBootTestContextBootstrapper=true"], contextCustomizers = [org.springframework.boot.webmvc.test.autoconfigure.WebDriverContextCustomizer@5003041b, org.springframework.boot.test.autoconfigure.OnFailureConditionReportContextCustomizerFactory$OnFailureConditionReportContextCustomizer@6bc248ed, [ImportsContextCustomizer@4228a2f6 key = [@org.springframework.test.context.BootstrapWith(org.springframework.boot.test.context.SpringBootTestContextBootstrapper.class), @org.springframework.stereotype.Indexed(), @org.springframework.boot.autoconfigure.SpringBootApplication(exclude={}, excludeName={}, nameGenerator=org.springframework.beans.factory.support.BeanNameGenerator.class, proxyBeanMethods=true, scanBasePackageClasses={}, scanBasePackages={}), @org.springframework.context.annotation.Import({org.springframework.boot.autoconfigure.AutoConfigurationImportSelector.class}), @org.springframework.boot.autoconfigure.EnableAutoConfiguration(exclude={}, excludeName={}), @org.springframework.context.annotation.ComponentScan(basePackageClasses={}, basePackages={}, excludeFilters={@org.springframework.context.annotation.ComponentScan.Filter(classes={org.springframework.boot.context.TypeExcludeFilter.class}, pattern={}, type=CUSTOM, value={org.springframework.boot.context.TypeExcludeFilter.class}), @org.springframework.context.annotation.ComponentScan.Filter(classes={org.springframework.boot.autoconfigure.AutoConfigurationExcludeFilter.class}, pattern={}, type=CUSTOM, value={org.springframework.boot.autoconfigure.AutoConfigurationExcludeFilter.class})}, includeFilters={}, lazyInit=false, nameGenerator=org.springframework.beans.factory.support.BeanNameGenerator.class, resourcePattern="**/*.class", scopeResolver=org.springframework.context.annotation.AnnotationScopeMetadataResolver.class, scopedProxy=DEFAULT, useDefaultFilters=true, value={}), @org.springframework.boot.test.context.SpringBootTest(args={}, classes={AppTestConfiguration.class, TestConfiguration.class}, properties={}, useMainMethod=NEVER, value={}, webEnvironment=DEFINED_PORT), @org.springframework.context.annotation.Import({org.springframework.boot.autoconfigure.AutoConfigurationPackages.Registrar.class}), @org.springframework.context.annotation.Configuration(enforceUniqueMethods=true, proxyBeanMethods=true, value=""), @org.springframework.context.annotation.Import({**redacted**, **redacted**, **redacted**, **redacted**, **redacted**}), @org.springframework.stereotype.Component(""), @org.apiguardian.api.API(consumers={"*"}, since="5.0", status=STABLE), @org.springframework.boot.autoconfigure.AutoConfigurationPackage(basePackageClasses={}, basePackages={}), @org.mockito.junit.jupiter.MockitoSettings(strictness=LENIENT), @org.springframework.boot.SpringBootConfiguration(proxyBeanMethods=true)]], org.springframework.boot.test.context.PropertyMappingContextCustomizer@0, org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@200a26bc, org.springframework.boot.test.http.client.DisableReactorResourceFactoryGlobalResourcesContextCustomizerFactory$DisableReactorResourceFactoryGlobalResourcesContextCustomizerCustomizer@2f66e802, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@2a492f2a, org.springframework.test.context.support.DynamicPropertiesContextCustomizer@0, org.springframework.boot.web.server.context.SpringBootTestRandomPortContextCustomizer@5a021cb9, org.springframework.boot.test.context.SpringBootTestAnnotation@50d6d588], resourceBasePath = "src/main/webapp", contextLoader = org.springframework.boot.test.context.SpringBootContextLoader, parent = null]
at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.lambda$loadContext$0(DefaultCacheAwareContextLoaderDelegate.java:195)
at org.springframework.test.context.cache.DefaultContextCache.put(DefaultContextCache.java:214)
at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:160)
at org.springframework.test.context.support.DefaultTestContext.getApplicationContext(DefaultTestContext.java:128)
at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.injectDependencies(DependencyInjectionTestExecutionListener.java:156)
at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.prepareTestInstance(DependencyInjectionTestExecutionListener.java:111)
at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:260)
at org.springframework.test.context.junit.jupiter.SpringExtension.postProcessTestInstance(SpringExtension.java:242)
at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:186)
at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:214)
at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:197)
at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:214)
at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1716)
at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:570)
at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:560)
at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:153)
at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:176)
at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:265)
at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:632)
at java.base/java.util.Optional.orElseGet(Optional.java:364)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1604)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1604)
Caused by: org.springframework.boot.context.properties.ConfigurationPropertiesBindException: Error creating bean with name 'TestProperties': Could not bind properties to 'TestProperties' : prefix=test, ignoreInvalidFields=false, ignoreUnknownFields=true
at org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor.bind(ConfigurationPropertiesBindingPostProcessor.java:104)
at org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor.postProcessBeforeInitialization(ConfigurationPropertiesBindingPostProcessor.java:84)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInitialization(AbstractAutowireCapableBeanFactory.java:426)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1807)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:603)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:525)
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:333)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:371)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:331)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:196)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.instantiateSingleton(DefaultListableBeanFactory.java:1225)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingleton(DefaultListableBeanFactory.java:1191)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:1121)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:994)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:621)
at org.springframework.boot.web.server.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:143)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:756)
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:445)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:321)
at org.springframework.boot.test.context.SpringBootContextLoader.lambda$loadContext$2(SpringBootContextLoader.java:155)
at org.springframework.util.function.ThrowingSupplier.get(ThrowingSupplier.java:58)
at org.springframework.util.function.ThrowingSupplier.get(ThrowingSupplier.java:46)
at org.springframework.boot.SpringApplication.withHook(SpringApplication.java:1465)
at org.springframework.boot.test.context.SpringBootContextLoader$ContextLoaderHook.run(SpringBootContextLoader.java:600)
at org.springframework.boot.test.context.SpringBootContextLoader.loadContext(SpringBootContextLoader.java:155)
at org.springframework.boot.test.context.SpringBootContextLoader.loadContext(SpringBootContextLoader.java:114)
at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContextInternal(DefaultCacheAwareContextLoaderDelegate.java:247)
at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.lambda$loadContext$0(DefaultCacheAwareContextLoaderDelegate.java:167)
... 21 more
Caused by: org.springframework.boot.context.properties.bind.BindException: Failed to bind properties under 'test.testmap' to java.util.Map<java.lang.String, java.lang.String>
at org.springframework.boot.context.properties.bind.Binder.handleBindError(Binder.java:419)
at org.springframework.boot.context.properties.bind.Binder.bind(Binder.java:378)
at org.springframework.boot.context.properties.bind.Binder.lambda$bindDataObject$0(Binder.java:508)
at org.springframework.boot.context.properties.bind.JavaBeanBinder.bind(JavaBeanBinder.java:127)
at org.springframework.boot.context.properties.bind.JavaBeanBinder.bind(JavaBeanBinder.java:115)
at org.springframework.boot.context.properties.bind.JavaBeanBinder.bind(JavaBeanBinder.java:71)
at org.springframework.boot.context.properties.bind.Binder.lambda$bindDataObject$2(Binder.java:511)
at org.springframework.boot.context.properties.bind.Binder.fromDataObjectBinders(Binder.java:521)
at org.springframework.boot.context.properties.bind.Binder.lambda$bindDataObject$1(Binder.java:510)
at org.springframework.boot.context.properties.bind.Binder$Context.withIncreasedDepth(Binder.java:636)
at org.springframework.boot.context.properties.bind.Binder$Context.withDataObject(Binder.java:622)
at org.springframework.boot.context.properties.bind.Binder.bindDataObject(Binder.java:513)
at org.springframework.boot.context.properties.bind.Binder.bindObject(Binder.java:448)
at org.springframework.boot.context.properties.bind.Binder.bind(Binder.java:374)
at org.springframework.boot.context.properties.bind.Binder.bind(Binder.java:361)
at org.springframework.boot.context.properties.bind.Binder.bind(Binder.java:288)
at org.springframework.boot.context.properties.bind.Binder.bind(Binder.java:275)
at org.springframework.boot.context.properties.ConfigurationPropertiesBinder.bind(ConfigurationPropertiesBinder.java:96)
at org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor.bind(ConfigurationPropertiesBindingPostProcessor.java:101)
... 48 more
Caused by: org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type [java.lang.String] to type [java.util.Map<java.lang.String, java.lang.String>]
at org.springframework.boot.context.properties.bind.BindConverter.convert(BindConverter.java:123)
at org.springframework.boot.context.properties.bind.BindConverter.convert(BindConverter.java:102)
at org.springframework.boot.context.properties.bind.BindConverter.convert(BindConverter.java:96)
at org.springframework.boot.context.properties.bind.MapBinder.bindAggregate(MapBinder.java:67)
at org.springframework.boot.context.properties.bind.AggregateBinder.bind(AggregateBinder.java:59)
at org.springframework.boot.context.properties.bind.Binder.lambda$bindAggregate$2(Binder.java:472)
at org.springframework.boot.context.properties.bind.Binder$Context.withIncreasedDepth(Binder.java:636)
at org.springframework.boot.context.properties.bind.Binder.bindAggregate(Binder.java:473)
at org.springframework.boot.context.properties.bind.Binder.bindObject(Binder.java:431)
at org.springframework.boot.context.properties.bind.Binder.bind(Binder.java:374)
... 65 more
Configuring a Map property with an empty collection is no longer possible in 4.1.0, was working in 4.0.6.
Instead of the application starting with an empty map for that property, the startup fails with an
Failed to load ApplicationContexterror caused by:e.g. with the following config class:
and this in application.yaml:
The result is an error at startup: