Closed
Description
We call PropertyResolver#getProperty(name, type)
in a few places. This method can throw a ConversionFailedException
which results in a lengthy, and not very helpful, stack trace such as:
2024-12-03T16:21:40,628Z ERROR o.s.b.SpringApplication:857 Application run failed java.lang.IllegalArgumentException: Invalid boolean value 'none'
at org.springframework.core.convert.support.StringToBooleanConverter.convert(StringToBooleanConverter.java:55)
at org.springframework.core.convert.support.StringToBooleanConverter.convert(StringToBooleanConverter.java:33)
at org.springframework.core.convert.support.GenericConversionService$ConverterAdapter.convert(GenericConversionService.java:358)
at org.springframework.core.convert.support.ConversionUtils.invokeConverter(ConversionUtils.java:41)
... 40 common frames omitted
Wrapped by: org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.lang.String] to type [java.lang.Boolean] for value [none]
at org.springframework.core.convert.support.ConversionUtils.invokeConverter(ConversionUtils.java:47)
at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:182)
at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:165)
at org.springframework.core.env.AbstractPropertyResolver.convertValueIfNecessary(AbstractPropertyResolver.java:281)
at org.springframework.boot.context.properties.source.ConfigurationPropertySourcesPropertyResolver.getProperty(ConfigurationPropertySourcesPropertyResolver.java:82)
at org.springframework.boot.context.properties.source.ConfigurationPropertySourcesPropertyResolver.getProperty(ConfigurationPropertySourcesPropertyResolver.java:66)
at org.springframework.core.env.AbstractEnvironment.getProperty(AbstractEnvironment.java:568)
at org.springframework.boot.actuate.autoconfigure.endpoint.PropertiesEndpointAccessResolver.determineDefaultAccess(PropertiesEndpointAccessResolver.java:65)
at org.springframework.boot.actuate.autoconfigure.endpoint.PropertiesEndpointAccessResolver.<init>(PropertiesEndpointAccessResolver.java:58)
at java.base/java.util.concurrent.ConcurrentMap.computeIfAbsent(ConcurrentMap.java:330)
at org.springframework.boot.actuate.autoconfigure.endpoint.condition.OnAvailableEndpointCondition.getAccess(OnAvailableEndpointCondition.java:136)
at org.springframework.boot.actuate.autoconfigure.endpoint.condition.OnAvailableEndpointCondition.getAccessOutcome(OnAvailableEndpointCondition.java:130)
at org.springframework.boot.actuate.autoconfigure.endpoint.condition.OnAvailableEndpointCondition.getMatchOutcome(OnAvailableEndpointCondition.java:117)
at org.springframework.boot.actuate.autoconfigure.endpoint.condition.OnAvailableEndpointCondition.getMatchOutcome(OnAvailableEndpointCondition.java:79)
at org.springframework.boot.autoconfigure.condition.SpringBootCondition.matches(SpringBootCondition.java:47)
... 26 common frames omitted
Wrapped by: java.lang.IllegalStateException: Error processing condition on org.springframework.boot.actuate.autoconfigure.audit.AuditEventsEndpointAutoConfiguration
at org.springframework.boot.autoconfigure.condition.SpringBootCondition.matches(SpringBootCondition.java:60)
at org.springframework.context.annotation.ConditionEvaluator.shouldSkip(ConditionEvaluator.java:99)
at org.springframework.context.annotation.ConfigurationClassParser.processConfigurationClass(ConfigurationClassParser.java:233)
at org.springframework.context.annotation.ConfigurationClassParser.processImports(ConfigurationClassParser.java:603)
... 23 common frames omitted
Wrapped by: org.springframework.beans.factory.BeanDefinitionStoreException: Failed to process import candidates for configuration class : Error processing condition on org.springframework.boot.actuate.autoconfigure.audit.AuditEventsEndpointAutoConfiguration
at org.springframework.context.annotation.ConfigurationClassParser.processImports(ConfigurationClassParser.java:613)
at org.springframework.context.annotation.ConfigurationClassParser$DeferredImportSelectorGroupingHandler.lambda$processGroupImports$1(ConfigurationClassParser.java:836)
at java.base/java.lang.Iterable.forEach(Iterable.java:75)
at org.springframework.context.annotation.ConfigurationClassParser$DeferredImportSelectorGroupingHandler.processGroupImports(ConfigurationClassParser.java:833)
at org.springframework.context.annotation.ConfigurationClassParser$DeferredImportSelectorHandler.process(ConfigurationClassParser.java:803)
at org.springframework.context.annotation.ConfigurationClassParser.parse(ConfigurationClassParser.java:189)
at org.springframework.context.annotation.ConfigurationClassPostProcessor.processConfigBeanDefinitions(ConfigurationClassPostProcessor.java:418)
at org.springframework.context.annotation.ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry(ConfigurationClassPostProcessor.java:290)
at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanDefinitionRegistryPostProcessors(PostProcessorRegistrationDelegate.java:349)
at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:118)
at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:791)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:609)
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:146)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:752)
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:439)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:318)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1361)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1350)
at Application.main(Application.java:16)
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
at java.base/java.lang.reflect.Method.invoke(Method.java:580)
at org.springframework.boot.loader.launch.Launcher.launch(Launcher.java:102)
at org.springframework.boot.loader.launch.Launcher.launch(Launcher.java:64)
at org.springframework.boot.loader.launch.JarLauncher.main(JarLauncher.java:40)
This could be improved by catching the ConversionFailedException
and throwing an InvalidConfigurationPropertyValueException
. The existing failure analysis will then kick in, turning the above into something more useful such as:
***************************
APPLICATION FAILED TO START
***************************
Description:
Invalid value 'none' for configuration property 'management.endpoints.enabled-by-default' (originating from 'System Environment Property "MANAGEMENT_ENDPOINTS_ENABLED_BY_DEFAULT"'). Validation failed for the following reason:
Failed to convert from type [java.lang.String] to type [java.lang.Boolean] for value [none]
Action:
Review the value of the property with the provided reason.
I'd like to discuss this with the team to see if we consider the current behavior to be a usability bug that should be fixed in a maintenance release or if this should be an enhancement for 3.5.x or later.