mirror of
https://github.com/spring-projects/spring-boot.git
synced 2026-10-04 08:19:50 +00:00
Bind Optional value object parameters as empty rather than null
Update `ValueObjectBinder` so that `Optional` parameters are bound as `Option.empty()` rather than `null`. See gh-49152 Signed-off-by: Ondřej Světlík <16480390+osvetlik@users.noreply.github.com>
This commit is contained in:
committed by
Phillip Webb
parent
e6472d8bc9
commit
4244dd933a
+7
-1
@@ -105,7 +105,13 @@ final class BindConverter {
|
||||
new ResolvableTypeDescriptor(targetType, targetAnnotations));
|
||||
}
|
||||
|
||||
private @Nullable Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
|
||||
@SuppressWarnings("unchecked")
|
||||
<T> @Nullable T convertNullValue(ResolvableType targetType, Annotation... targetAnnotations) {
|
||||
return (T) convert(null, null, new ResolvableTypeDescriptor(targetType, targetAnnotations));
|
||||
}
|
||||
|
||||
private @Nullable Object convert(@Nullable Object source, @Nullable TypeDescriptor sourceType,
|
||||
TypeDescriptor targetType) {
|
||||
ConversionException failure = null;
|
||||
for (ConversionService delegate : this.delegates) {
|
||||
try {
|
||||
|
||||
+6
-1
@@ -132,7 +132,12 @@ class ValueObjectBinder implements DataObjectBinder {
|
||||
return convertDefaultValue(context.getConverter(), defaultValue, type, annotations);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
return convertNullValue(context, type);
|
||||
}
|
||||
|
||||
private <T> @Nullable T convertNullValue(Binder.Context context, ResolvableType type, Annotation... annotations) {
|
||||
BindConverter converter = context.getConverter();
|
||||
return converter.convertNullValue(type, annotations);
|
||||
}
|
||||
|
||||
private <T> @Nullable T convertDefaultValue(BindConverter converter, String[] defaultValue, ResolvableType type,
|
||||
|
||||
+27
@@ -326,6 +326,25 @@ class ValueObjectBinderTests {
|
||||
assertThat(bound.getOptionalValue()).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
void bindWhenOptionalParameterWithNoValueForPrimitiveShouldReturnEmptyInstance() {
|
||||
RecordPropertiesWithOptional bound = this.binder.bindOrCreate("foo",
|
||||
Bindable.of(RecordPropertiesWithOptional.class));
|
||||
assertThat(bound.property1()).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
void bindWhenOptionalParameterInNestedWithNoValueForPrimitiveShouldReturnEmptyInstance() {
|
||||
MockConfigurationPropertySource source = new MockConfigurationPropertySource();
|
||||
source.put("foo.nested.property2", "str");
|
||||
this.sources.add(source);
|
||||
RecordPropertiesWithOptionalInNestedRecord bound = this.binder.bindOrCreate("foo",
|
||||
Bindable.of(RecordPropertiesWithOptionalInNestedRecord.class));
|
||||
assertThat(bound.nested()).isNotNull();
|
||||
assertThat(bound.nested().property1()).isNotNull().isEmpty();
|
||||
assertThat(bound.nested().property2()).isEqualTo("str");
|
||||
}
|
||||
|
||||
@Test
|
||||
void bindWhenEnumParameterWithEmptyDefaultValueShouldThrowException() {
|
||||
assertThatExceptionOfType(BindException.class)
|
||||
@@ -902,6 +921,14 @@ class ValueObjectBinderTests {
|
||||
@DefaultValue("default-value-2") String property2) {
|
||||
}
|
||||
|
||||
record RecordPropertiesWithOptional(Optional<String> property1) {
|
||||
}
|
||||
|
||||
record RecordPropertiesWithOptionalInNestedRecord(NestedRecord nested) {
|
||||
record NestedRecord(Optional<String> property1, String property2) {
|
||||
}
|
||||
}
|
||||
|
||||
static class NonExtractableParameterName {
|
||||
|
||||
private @Nullable String value;
|
||||
|
||||
Reference in New Issue
Block a user