Skip to content

Commit 4d838c1

Browse files
HeartPatternrstoyanchev
authored andcommitted
Exclude Part from nested constructor binding in WebFlux
See gh-31778
1 parent c75c0ae commit 4d838c1

File tree

2 files changed

+43
-0
lines changed

2 files changed

+43
-0
lines changed

spring-web/src/main/java/org/springframework/web/bind/support/WebExchangeDataBinder.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
import java.util.Map;
2121
import java.util.TreeMap;
2222

23+
import org.springframework.core.MethodParameter;
24+
import org.springframework.web.multipart.MultipartFile;
2325
import reactor.core.publisher.Mono;
2426

2527
import org.springframework.beans.MutablePropertyValues;
@@ -87,6 +89,13 @@ public Mono<Void> construct(ServerWebExchange exchange) {
8789
.then();
8890
}
8991

92+
@Override
93+
protected boolean shouldConstructArgument(MethodParameter param) {
94+
Class<?> type = param.nestedIfOptional().getNestedParameterType();
95+
return (super.shouldConstructArgument(param) &&
96+
!MultipartFile.class.isAssignableFrom(type) && !Part.class.isAssignableFrom(type));
97+
}
98+
9099
/**
91100
* Bind query parameters, form data, or multipart form data to the binder target.
92101
* @param exchange the current exchange

spring-web/src/test/java/org/springframework/web/bind/support/WebExchangeDataBinderTests.java

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828

2929
import org.springframework.beans.testfixture.beans.ITestBean;
3030
import org.springframework.beans.testfixture.beans.TestBean;
31+
import org.springframework.core.ResolvableType;
3132
import org.springframework.core.io.ClassPathResource;
3233
import org.springframework.http.HttpMethod;
3334
import org.springframework.http.MediaType;
@@ -219,6 +220,19 @@ public void testMultipart() throws Exception {
219220
assertThat(bean.getSomePartList().get(1).filename()).isEqualTo("spring.png");
220221
}
221222

223+
@Test
224+
public void testConstructorMultipart() throws Exception {
225+
WebExchangeDataBinder binder = new WebExchangeDataBinder(null);
226+
binder.setTargetType(ResolvableType.forClass(ConstructorMultipartBean.class));
227+
228+
MultiValueMap<String, Object> data = new LinkedMultiValueMap<>();
229+
data.add("part", new ClassPathResource("org/springframework/http/codec/multipart/foo.txt"));
230+
binder.construct(exchangeMultipart(data)).block(Duration.ofMillis(5000));
231+
ConstructorMultipartBean bean = (ConstructorMultipartBean) binder.getTarget();
232+
233+
assertThat(bean.getPart().filename()).isEqualTo("foo.txt");
234+
assertThat(bean.getNullableFilePart()).isNull();
235+
}
222236

223237

224238
private ServerWebExchange exchange(MultiValueMap<String, String> formData) {
@@ -313,4 +327,24 @@ public void setSomePartList(List<FilePart> somePartList) {
313327
}
314328
}
315329

330+
private static class ConstructorMultipartBean {
331+
private final FilePart part;
332+
private final FilePart nullableFilePart;
333+
334+
public ConstructorMultipartBean(
335+
FilePart part,
336+
FilePart nullableFilePart
337+
) {
338+
this.part = part;
339+
this.nullableFilePart = nullableFilePart;
340+
}
341+
342+
public FilePart getPart() {
343+
return part;
344+
}
345+
346+
public FilePart getNullableFilePart() {
347+
return nullableFilePart;
348+
}
349+
}
316350
}

0 commit comments

Comments
 (0)