diff --git a/spring-web/src/main/java/org/springframework/web/service/invoker/AbstractNamedValueArgumentResolver.java b/spring-web/src/main/java/org/springframework/web/service/invoker/AbstractNamedValueArgumentResolver.java index 238a5e85862..3a967ed0c7d 100644 --- a/spring-web/src/main/java/org/springframework/web/service/invoker/AbstractNamedValueArgumentResolver.java +++ b/spring-web/src/main/java/org/springframework/web/service/invoker/AbstractNamedValueArgumentResolver.java @@ -32,6 +32,7 @@ import org.springframework.core.convert.TypeDescriptor; import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; +import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.ValueConstants; /** @@ -191,11 +192,15 @@ public abstract class AbstractNamedValueArgumentResolver implements HttpServiceA } if (this.conversionService != null && !(value instanceof String)) { + Object beforeValue = value; parameter = parameter.nestedIfOptional(); Class type = parameter.getNestedParameterType(); value = (type != Object.class && !type.isArray() ? this.conversionService.convert(value, new TypeDescriptor(parameter), STRING_TARGET_TYPE) : this.conversionService.convert(value, String.class)); + if (!StringUtils.hasText((String) value) && !required && beforeValue == null) { + value = null; + } } if (value == null) { diff --git a/spring-web/src/test/java/org/springframework/web/service/invoker/NamedValueArgumentResolverTests.java b/spring-web/src/test/java/org/springframework/web/service/invoker/NamedValueArgumentResolverTests.java index cbac555179a..4e677140b52 100644 --- a/spring-web/src/test/java/org/springframework/web/service/invoker/NamedValueArgumentResolverTests.java +++ b/spring-web/src/test/java/org/springframework/web/service/invoker/NamedValueArgumentResolverTests.java @@ -74,6 +74,12 @@ class NamedValueArgumentResolverTests { assertTestValue("value", "2022-09-16"); } + @Test // gh-33794 + void dateNullValue() { + this.service.executeDate(null); + assertTestValue("value"); + } + @Test void objectTestValue() { this.service.execute(Boolean.TRUE); @@ -182,7 +188,7 @@ class NamedValueArgumentResolverTests { void executeString(@TestValue String value); @GetExchange - void executeDate(@TestValue @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate value); + void executeDate(@Nullable @TestValue(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate value); @GetExchange void execute(@TestValue Object value);