diff --git a/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestBodyArgumentResolver.java b/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestBodyArgumentResolver.java index fca79df098d..7c82bbdfcc3 100644 --- a/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestBodyArgumentResolver.java +++ b/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestBodyArgumentResolver.java @@ -25,7 +25,6 @@ import reactor.core.publisher.Mono; import org.springframework.core.MethodParameter; import org.springframework.core.ResolvableType; import org.springframework.core.convert.ConversionService; -import org.springframework.core.io.buffer.DataBuffer; import org.springframework.http.MediaType; import org.springframework.http.converter.reactive.HttpMessageConverter; import org.springframework.ui.ModelMap; @@ -35,8 +34,13 @@ import org.springframework.web.reactive.result.method.HandlerMethodArgumentResol import org.springframework.web.server.ServerWebExchange; /** + * Resolves method arguments annotated with {@code @RequestBody} by reading and + * decoding the body of the request through a compatible + * {@code HttpMessageConverter}. + * * @author Sebastien Deleuze * @author Stephane Maldini + * @author Rossen Stoyanchev */ public class RequestBodyArgumentResolver implements HandlerMethodArgumentResolver { @@ -44,15 +48,30 @@ public class RequestBodyArgumentResolver implements HandlerMethodArgumentResolve private final ConversionService conversionService; - public RequestBodyArgumentResolver(List> messageConverters, + + /** + * Constructor with message converters and a ConversionService. + * @param converters converters for reading the request body with + * @param service for converting to other reactive types from Flux and Mono + */ + public RequestBodyArgumentResolver(List> converters, ConversionService service) { - Assert.notEmpty(messageConverters, "At least one message converter is required."); + + Assert.notEmpty(converters, "At least one message converter is required."); Assert.notNull(service, "'conversionService' is required."); - this.messageConverters = messageConverters; + this.messageConverters = converters; this.conversionService = service; } + /** + * Return the configured message converters. + */ + public List> getMessageConverters() { + return this.messageConverters; + } + + @Override public boolean supportsParameter(MethodParameter parameter) { return parameter.hasParameterAnnotation(RequestBody.class); @@ -70,35 +89,29 @@ public class RequestBodyArgumentResolver implements HandlerMethodArgumentResolve mediaType = MediaType.APPLICATION_OCTET_STREAM; } - Flux body = exchange.getRequest().getBody(); - Flux elementFlux; + Flux elementFlux = exchange.getRequest().getBody(); - HttpMessageConverter messageConverter = - resolveMessageConverter(elementType, mediaType); - if (messageConverter != null) { - elementFlux = messageConverter.read(elementType, exchange.getRequest()); - } - else { - elementFlux = body; + HttpMessageConverter converter = getMessageConverter(elementType, mediaType); + if (converter != null) { + elementFlux = converter.read(elementType, exchange.getRequest()); } - if (this.conversionService.canConvert(Publisher.class, type.getRawClass())) { - return Mono.just(this.conversionService - .convert(elementFlux, type.getRawClass())); - } - else if (type.getRawClass() == Flux.class) { + if (type.getRawClass() == Flux.class) { return Mono.just(elementFlux); } else if (type.getRawClass() == Mono.class) { return Mono.just(Mono.from(elementFlux)); } + else if (this.conversionService.canConvert(Publisher.class, type.getRawClass())) { + Object target = this.conversionService.convert(elementFlux, type.getRawClass()); + return Mono.just(target); + } // TODO Currently manage only "Foo" parameter, not "List" parameters, Stéphane is going to add toIterable/toIterator to Flux to support that use case return elementFlux.next().map(o -> o); } - private HttpMessageConverter resolveMessageConverter(ResolvableType type, - MediaType mediaType) { + private HttpMessageConverter getMessageConverter(ResolvableType type, MediaType mediaType) { for (HttpMessageConverter messageConverter : this.messageConverters) { if (messageConverter.canRead(type, mediaType)) { return messageConverter; diff --git a/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/ResponseBodyResultHandler.java b/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/ResponseBodyResultHandler.java index 56f7886ffea..6a04b69091d 100644 --- a/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/ResponseBodyResultHandler.java +++ b/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/ResponseBodyResultHandler.java @@ -78,14 +78,6 @@ public class ResponseBodyResultHandler extends ContentNegotiatingResultHandlerSu this(converters, conversionService, new HeaderContentTypeResolver()); } - - /** - * Return the configured message converters. - */ - public List> getMessageConverters() { - return this.messageConverters; - } - /** * Constructor with message converters, a {@code ConversionService}, and a * {@code RequestedContentTypeResolver}. @@ -105,6 +97,13 @@ public class ResponseBodyResultHandler extends ContentNegotiatingResultHandlerSu } + /** + * Return the configured message converters. + */ + public List> getMessageConverters() { + return this.messageConverters; + } + @Override public boolean supports(HandlerResult result) { Object handler = result.getHandler();