Skip to content

Commit a5c2f0f

Browse files
wilkinsonaphilwebb
andcommitted
Improve diagnostics when config prop value conversion fails
Closes gh-43378 Co-Authored-By: Phillip Webb <[email protected]>
1 parent 88fad3c commit a5c2f0f

File tree

3 files changed

+41
-2
lines changed

3 files changed

+41
-2
lines changed

Diff for: spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/source/ConfigurationPropertySourcesPropertyResolver.java

+9-1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
package org.springframework.boot.context.properties.source;
1818

19+
import org.springframework.core.convert.ConversionFailedException;
1920
import org.springframework.core.env.AbstractPropertyResolver;
2021
import org.springframework.core.env.MutablePropertySources;
2122
import org.springframework.core.env.PropertySources;
@@ -79,7 +80,14 @@ private <T> T getProperty(String key, Class<T> targetValueType, boolean resolveN
7980
if (resolveNestedPlaceholders && value instanceof String string) {
8081
value = resolveNestedPlaceholders(string);
8182
}
82-
return convertValueIfNecessary(value, targetValueType);
83+
try {
84+
return convertValueIfNecessary(value, targetValueType);
85+
}
86+
catch (ConversionFailedException ex) {
87+
Exception wrappedCause = new InvalidConfigurationPropertyValueException(key, value,
88+
"Failed to convert to type " + ex.getTargetType(), ex.getCause());
89+
throw new ConversionFailedException(ex.getSourceType(), ex.getTargetType(), ex.getValue(), wrappedCause);
90+
}
8391
}
8492

8593
private Object findPropertyValue(String key) {

Diff for: spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/source/InvalidConfigurationPropertyValueException.java

+5-1
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,11 @@ public class InvalidConfigurationPropertyValueException extends RuntimeException
4343
* returns are allowed.
4444
*/
4545
public InvalidConfigurationPropertyValueException(String name, Object value, String reason) {
46-
super("Property " + name + " with value '" + value + "' is invalid: " + reason);
46+
this(name, value, reason, null);
47+
}
48+
49+
InvalidConfigurationPropertyValueException(String name, Object value, String reason, Throwable cause) {
50+
super("Property " + name + " with value '" + value + "' is invalid: " + reason, cause);
4751
Assert.notNull(name, "Name must not be null");
4852
this.name = name;
4953
this.value = value;

Diff for: spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/source/ConfigurationPropertySourcesPropertyResolverTests.java

+27
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,15 @@
2222

2323
import org.junit.jupiter.api.Test;
2424

25+
import org.springframework.core.convert.ConversionFailedException;
26+
import org.springframework.core.convert.TypeDescriptor;
2527
import org.springframework.core.env.ConfigurablePropertyResolver;
2628
import org.springframework.core.env.MutablePropertySources;
2729
import org.springframework.core.env.StandardEnvironment;
2830
import org.springframework.mock.env.MockPropertySource;
2931

3032
import static org.assertj.core.api.Assertions.assertThat;
33+
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
3134

3235
/**
3336
* Tests for {@link ConfigurationPropertySourcesPropertyResolver}.
@@ -113,6 +116,30 @@ void getPropertyAsTypeWhenHasPlaceholder() {
113116
assertThat(environment.getProperty("v2", Integer.class)).isOne();
114117
}
115118

119+
@Test
120+
void throwsInvalidConfigurationPropertyValueExceptionWhenGetPropertyAsTypeFailsToConvert() {
121+
ResolverEnvironment environment = new ResolverEnvironment();
122+
MockPropertySource propertySource = new MockPropertySource();
123+
propertySource.withProperty("v1", "one");
124+
propertySource.withProperty("v2", "${v1}");
125+
environment.getPropertySources().addFirst(propertySource);
126+
assertThat(environment.getProperty("v2")).isEqualTo("one");
127+
assertThatExceptionOfType(ConversionFailedException.class)
128+
.isThrownBy(() -> environment.getProperty("v2", Integer.class))
129+
.satisfies((ex) -> {
130+
assertThat(ex.getValue()).isEqualTo("one");
131+
assertThat(ex.getSourceType()).isEqualTo(TypeDescriptor.valueOf(String.class));
132+
assertThat(ex.getTargetType()).isEqualTo(TypeDescriptor.valueOf(Integer.class));
133+
})
134+
.havingCause()
135+
.satisfies((ex) -> {
136+
InvalidConfigurationPropertyValueException invalidValueEx = (InvalidConfigurationPropertyValueException) ex;
137+
assertThat(invalidValueEx.getName()).isEqualTo("v2");
138+
assertThat(invalidValueEx.getValue()).isEqualTo("one");
139+
assertThat(ex).cause().isInstanceOf(NumberFormatException.class);
140+
});
141+
}
142+
116143
private CountingMockPropertySource createMockPropertySource(StandardEnvironment environment, boolean attach) {
117144
CountingMockPropertySource propertySource = new CountingMockPropertySource();
118145
propertySource.withProperty("spring", "boot");

0 commit comments

Comments
 (0)