diff --git a/spring-web/src/main/java/org/springframework/web/bind/support/WebExchangeDataBinder.java b/spring-web/src/main/java/org/springframework/web/bind/support/WebExchangeDataBinder.java index 38e09275194f..99a2d55abe1b 100644 --- a/spring-web/src/main/java/org/springframework/web/bind/support/WebExchangeDataBinder.java +++ b/spring-web/src/main/java/org/springframework/web/bind/support/WebExchangeDataBinder.java @@ -20,6 +20,8 @@ import java.util.Map; import java.util.TreeMap; +import org.springframework.core.MethodParameter; +import org.springframework.web.multipart.MultipartFile; import reactor.core.publisher.Mono; import org.springframework.beans.MutablePropertyValues; @@ -87,6 +89,13 @@ public Mono construct(ServerWebExchange exchange) { .then(); } + @Override + protected boolean shouldConstructArgument(MethodParameter param) { + Class type = param.nestedIfOptional().getNestedParameterType(); + return (super.shouldConstructArgument(param) && + !MultipartFile.class.isAssignableFrom(type) && !Part.class.isAssignableFrom(type)); + } + /** * Bind query parameters, form data, or multipart form data to the binder target. * @param exchange the current exchange diff --git a/spring-web/src/test/java/org/springframework/web/bind/support/WebExchangeDataBinderTests.java b/spring-web/src/test/java/org/springframework/web/bind/support/WebExchangeDataBinderTests.java index 7fdd726d4b05..c222631ba444 100644 --- a/spring-web/src/test/java/org/springframework/web/bind/support/WebExchangeDataBinderTests.java +++ b/spring-web/src/test/java/org/springframework/web/bind/support/WebExchangeDataBinderTests.java @@ -28,6 +28,7 @@ import org.springframework.beans.testfixture.beans.ITestBean; import org.springframework.beans.testfixture.beans.TestBean; +import org.springframework.core.ResolvableType; import org.springframework.core.io.ClassPathResource; import org.springframework.http.HttpMethod; import org.springframework.http.MediaType; @@ -219,6 +220,19 @@ public void testMultipart() throws Exception { assertThat(bean.getSomePartList().get(1).filename()).isEqualTo("spring.png"); } + @Test + public void testConstructorMultipart() throws Exception { + WebExchangeDataBinder binder = new WebExchangeDataBinder(null); + binder.setTargetType(ResolvableType.forClass(ConstructorMultipartBean.class)); + + MultiValueMap data = new LinkedMultiValueMap<>(); + data.add("part", new ClassPathResource("org/springframework/http/codec/multipart/foo.txt")); + binder.construct(exchangeMultipart(data)).block(Duration.ofMillis(5000)); + ConstructorMultipartBean bean = (ConstructorMultipartBean) binder.getTarget(); + + assertThat(bean.getPart().filename()).isEqualTo("foo.txt"); + assertThat(bean.getNullableFilePart()).isNull(); + } private ServerWebExchange exchange(MultiValueMap formData) { @@ -313,4 +327,24 @@ public void setSomePartList(List somePartList) { } } + private static class ConstructorMultipartBean { + private final FilePart part; + private final FilePart nullableFilePart; + + public ConstructorMultipartBean( + FilePart part, + FilePart nullableFilePart + ) { + this.part = part; + this.nullableFilePart = nullableFilePart; + } + + public FilePart getPart() { + return part; + } + + public FilePart getNullableFilePart() { + return nullableFilePart; + } + } }