WebFlux @RequestPart support for List and Flux arguments

The resolver now supports List<T>, Flux<T>, and List<Part>.

Issue: SPR-16621
This commit is contained in:
Rossen Stoyanchev
2018-05-11 18:38:29 -04:00
parent 15182b29a4
commit 5cee607f28
2 changed files with 298 additions and 16 deletions

View File

@@ -74,35 +74,49 @@ public class RequestPartMethodArgumentResolver extends AbstractMessageReaderArgu
boolean isRequired = (requestPart == null || requestPart.required());
String name = getPartName(parameter, requestPart);
Flux<Part> values = exchange.getMultipartData()
Flux<Part> parts = exchange.getMultipartData()
.flatMapMany(map -> {
List<Part> parts = map.get(name);
if (CollectionUtils.isEmpty(parts)) {
List<Part> list = map.get(name);
if (CollectionUtils.isEmpty(list)) {
return isRequired ?
Flux.error(getMissingPartException(name, parameter)) :
Flux.empty();
}
return Flux.fromIterable(parts);
return Flux.fromIterable(list);
});
ReactiveAdapter adapter = getAdapterRegistry().getAdapter(parameter.getParameterType());
MethodParameter elementType = adapter != null ? parameter.nested() : parameter;
if (Part.class.isAssignableFrom(parameter.getParameterType())) {
return parts.next().cast(Object.class);
}
if (Part.class.isAssignableFrom(elementType.getNestedParameterType())) {
if (adapter != null) {
values = adapter.isMultiValue() ? values : values.take(1);
return Mono.just(adapter.fromPublisher(values));
if (List.class.isAssignableFrom(parameter.getParameterType())) {
MethodParameter elementType = parameter.nested();
if (Part.class.isAssignableFrom(elementType.getNestedParameterType())) {
return parts.collectList().cast(Object.class);
}
else {
return values.next().cast(Object.class);
return decodePartValues(parts, elementType, bindingContext, exchange, isRequired)
.collectList().cast(Object.class);
}
}
return values.next().flatMap(part -> {
ServerHttpRequest partRequest = new PartServerHttpRequest(exchange.getRequest(), part);
ServerWebExchange partExchange = exchange.mutate().request(partRequest).build();
return readBody(parameter, isRequired, bindingContext, partExchange);
});
ReactiveAdapter adapter = getAdapterRegistry().getAdapter(parameter.getParameterType());
if (adapter != null) {
// Mono<Part> or Flux<Part>
MethodParameter elementType = parameter.nested();
if (Part.class.isAssignableFrom(elementType.getNestedParameterType())) {
parts = adapter.isMultiValue() ? parts : parts.take(1);
return Mono.just(adapter.fromPublisher(parts));
}
// We have to decode the content for each part, one at a time
if (adapter.isMultiValue()) {
return Mono.just(decodePartValues(parts, elementType, bindingContext, exchange, isRequired));
}
}
// <T> or Mono<T>
return decodePartValues(parts, parameter, bindingContext, exchange, isRequired)
.next().cast(Object.class);
}
private String getPartName(MethodParameter methodParam, @Nullable RequestPart requestPart) {
@@ -124,6 +138,17 @@ public class RequestPartMethodArgumentResolver extends AbstractMessageReaderArgu
}
private Flux<?> decodePartValues(Flux<Part> parts, MethodParameter elementType, BindingContext bindingContext,
ServerWebExchange exchange, boolean isRequired) {
return parts.flatMap(part -> {
ServerHttpRequest partRequest = new PartServerHttpRequest(exchange.getRequest(), part);
ServerWebExchange partExchange = exchange.mutate().request(partRequest).build();
return readBody(elementType, isRequired, bindingContext, partExchange);
});
}
private static class PartServerHttpRequest extends ServerHttpRequestDecorator {
private final Part part;