Add ReactiveHttpRequestValues
Separate collection and handling of reactive request values into a subclass of HttpRequestValues. Closes gh-30117
This commit is contained in:
@@ -27,10 +27,10 @@ import org.reactivestreams.Publisher;
|
|||||||
|
|
||||||
import org.springframework.core.ParameterizedTypeReference;
|
import org.springframework.core.ParameterizedTypeReference;
|
||||||
import org.springframework.core.ResolvableType;
|
import org.springframework.core.ResolvableType;
|
||||||
|
import org.springframework.http.HttpEntity;
|
||||||
import org.springframework.http.HttpHeaders;
|
import org.springframework.http.HttpHeaders;
|
||||||
import org.springframework.http.HttpMethod;
|
import org.springframework.http.HttpMethod;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.http.client.MultipartBodyBuilder;
|
|
||||||
import org.springframework.lang.Nullable;
|
import org.springframework.lang.Nullable;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
import org.springframework.util.CollectionUtils;
|
import org.springframework.util.CollectionUtils;
|
||||||
@@ -48,7 +48,7 @@ import org.springframework.web.util.UriUtils;
|
|||||||
* @author Rossen Stoyanchev
|
* @author Rossen Stoyanchev
|
||||||
* @since 6.0
|
* @since 6.0
|
||||||
*/
|
*/
|
||||||
public final class HttpRequestValues {
|
public class HttpRequestValues {
|
||||||
|
|
||||||
private static final MultiValueMap<String, String> EMPTY_COOKIES_MAP =
|
private static final MultiValueMap<String, String> EMPTY_COOKIES_MAP =
|
||||||
CollectionUtils.toMultiValueMap(Collections.emptyMap());
|
CollectionUtils.toMultiValueMap(Collections.emptyMap());
|
||||||
@@ -74,18 +74,11 @@ public final class HttpRequestValues {
|
|||||||
@Nullable
|
@Nullable
|
||||||
private final Object bodyValue;
|
private final Object bodyValue;
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private final Publisher<?> body;
|
|
||||||
|
|
||||||
@Nullable
|
protected HttpRequestValues(@Nullable HttpMethod httpMethod,
|
||||||
private final ParameterizedTypeReference<?> bodyElementType;
|
|
||||||
|
|
||||||
|
|
||||||
private HttpRequestValues(@Nullable HttpMethod httpMethod,
|
|
||||||
@Nullable URI uri, @Nullable String uriTemplate, Map<String, String> uriVariables,
|
@Nullable URI uri, @Nullable String uriTemplate, Map<String, String> uriVariables,
|
||||||
HttpHeaders headers, MultiValueMap<String, String> cookies, Map<String, Object> attributes,
|
HttpHeaders headers, MultiValueMap<String, String> cookies, Map<String, Object> attributes,
|
||||||
@Nullable Object bodyValue,
|
@Nullable Object bodyValue) {
|
||||||
@Nullable Publisher<?> body, @Nullable ParameterizedTypeReference<?> bodyElementType) {
|
|
||||||
|
|
||||||
Assert.isTrue(uri != null || uriTemplate != null, "Neither URI nor URI template");
|
Assert.isTrue(uri != null || uriTemplate != null, "Neither URI nor URI template");
|
||||||
|
|
||||||
@@ -97,8 +90,6 @@ public final class HttpRequestValues {
|
|||||||
this.cookies = cookies;
|
this.cookies = cookies;
|
||||||
this.attributes = attributes;
|
this.attributes = attributes;
|
||||||
this.bodyValue = bodyValue;
|
this.bodyValue = bodyValue;
|
||||||
this.body = body;
|
|
||||||
this.bodyElementType = bodyElementType;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -161,8 +152,6 @@ public final class HttpRequestValues {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the request body as a value to be serialized, if set.
|
* Return the request body as a value to be serialized, if set.
|
||||||
* <p>This is mutually exclusive with {@link #getBody()}.
|
|
||||||
* Only one of the two or neither is set.
|
|
||||||
*/
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
public Object getBodyValue() {
|
public Object getBodyValue() {
|
||||||
@@ -173,18 +162,24 @@ public final class HttpRequestValues {
|
|||||||
* Return the request body as a Publisher.
|
* Return the request body as a Publisher.
|
||||||
* <p>This is mutually exclusive with {@link #getBodyValue()}.
|
* <p>This is mutually exclusive with {@link #getBodyValue()}.
|
||||||
* Only one of the two or neither is set.
|
* Only one of the two or neither is set.
|
||||||
|
* @deprecated in favor of {@link ReactiveHttpRequestValues#getBodyPublisher()};
|
||||||
|
* to be removed in 6.2
|
||||||
*/
|
*/
|
||||||
|
@Deprecated(since = "6.1", forRemoval = true)
|
||||||
@Nullable
|
@Nullable
|
||||||
public Publisher<?> getBody() {
|
public Publisher<?> getBody() {
|
||||||
return this.body;
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the element type for a {@linkplain #getBody() Publisher body}.
|
* Return the element type for a Publisher body.
|
||||||
|
* @deprecated in favor of {@link ReactiveHttpRequestValues#getBodyPublisherElementType()};
|
||||||
|
* to be removed in 6.2
|
||||||
*/
|
*/
|
||||||
|
@Deprecated(since = "6.1", forRemoval = true)
|
||||||
@Nullable
|
@Nullable
|
||||||
public ParameterizedTypeReference<?> getBodyElementType() {
|
public ParameterizedTypeReference<?> getBodyElementType() {
|
||||||
return this.bodyElementType;
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -196,7 +191,7 @@ public final class HttpRequestValues {
|
|||||||
/**
|
/**
|
||||||
* Builder for {@link HttpRequestValues}.
|
* Builder for {@link HttpRequestValues}.
|
||||||
*/
|
*/
|
||||||
public final static class Builder {
|
public static class Builder {
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private HttpMethod httpMethod;
|
private HttpMethod httpMethod;
|
||||||
@@ -220,7 +215,7 @@ public final class HttpRequestValues {
|
|||||||
private MultiValueMap<String, String> requestParams;
|
private MultiValueMap<String, String> requestParams;
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private MultipartBodyBuilder multipartBuilder;
|
private MultiValueMap<String, Object> parts;
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private Map<String, Object> attributes;
|
private Map<String, Object> attributes;
|
||||||
@@ -228,12 +223,6 @@ public final class HttpRequestValues {
|
|||||||
@Nullable
|
@Nullable
|
||||||
private Object bodyValue;
|
private Object bodyValue;
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private Publisher<?> body;
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private ParameterizedTypeReference<?> bodyElementType;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the HTTP method for the request.
|
* Set the HTTP method for the request.
|
||||||
*/
|
*/
|
||||||
@@ -327,23 +316,30 @@ public final class HttpRequestValues {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a part to a multipart request. The part value may be as described
|
* Add a part for a multipart request. The part may be:
|
||||||
* in {@link MultipartBodyBuilder#part(String, Object)}.
|
* <ul>
|
||||||
|
* <li>String -- form field
|
||||||
|
* <li>{@link org.springframework.core.io.Resource Resource} -- file part
|
||||||
|
* <li>Object -- content to be encoded (e.g. to JSON)
|
||||||
|
* <li>{@link HttpEntity} -- part content and headers although generally it's
|
||||||
|
* easier to add headers through the returned builder
|
||||||
|
* </ul>
|
||||||
*/
|
*/
|
||||||
public Builder addRequestPart(String name, Object part) {
|
public Builder addRequestPart(String name, Object part) {
|
||||||
this.multipartBuilder = (this.multipartBuilder != null ? this.multipartBuilder : new MultipartBodyBuilder());
|
this.parts = (this.parts != null ? this.parts : new LinkedMultiValueMap<>());
|
||||||
this.multipartBuilder.part(name, part);
|
this.parts.add(name, part);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Variant of {@link #addRequestPart(String, Object)} that allows the
|
* Variant of {@link #addRequestPart(String, Object)} that allows the
|
||||||
* part value to be produced by a {@link Publisher}.
|
* part value to be produced by a {@link Publisher}.
|
||||||
|
* @deprecated in favor of {@link ReactiveHttpRequestValues.Builder#addRequestPartPublisher};
|
||||||
|
* to be removed in 6.2
|
||||||
*/
|
*/
|
||||||
|
@Deprecated(since = "6.1", forRemoval = true)
|
||||||
public <T, P extends Publisher<T>> Builder addRequestPart(String name, P publisher, ResolvableType type) {
|
public <T, P extends Publisher<T>> Builder addRequestPart(String name, P publisher, ResolvableType type) {
|
||||||
this.multipartBuilder = (this.multipartBuilder != null ? this.multipartBuilder : new MultipartBodyBuilder());
|
throw new UnsupportedOperationException();
|
||||||
this.multipartBuilder.asyncPart(name, publisher, ParameterizedTypeReference.forType(type.getType()));
|
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -358,25 +354,22 @@ public final class HttpRequestValues {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the request body as a concrete value to be serialized.
|
* Set the request body as an Object to be serialized.
|
||||||
* <p>This is mutually exclusive with, and resets any previously set
|
|
||||||
* {@linkplain #setBody(Publisher, ParameterizedTypeReference) body Publisher}.
|
|
||||||
*/
|
*/
|
||||||
public void setBodyValue(Object bodyValue) {
|
public void setBodyValue(Object bodyValue) {
|
||||||
this.bodyValue = bodyValue;
|
this.bodyValue = bodyValue;
|
||||||
this.body = null;
|
|
||||||
this.bodyElementType = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the request body as a concrete value to be serialized.
|
* Set the request body as a Reactive Streams Publisher.
|
||||||
* <p>This is mutually exclusive with, and resets any previously set
|
* <p>This is mutually exclusive with, and resets any previously set
|
||||||
* {@linkplain #setBodyValue(Object) body value}.
|
* {@linkplain #setBodyValue(Object) body value}.
|
||||||
|
* @deprecated in favor of {@link ReactiveHttpRequestValues.Builder#setBodyPublisher};
|
||||||
|
* to be removed in 6.2
|
||||||
*/
|
*/
|
||||||
|
@Deprecated(since = "6.1", forRemoval = true)
|
||||||
public <T, P extends Publisher<T>> void setBody(P body, ParameterizedTypeReference<T> elementTye) {
|
public <T, P extends Publisher<T>> void setBody(P body, ParameterizedTypeReference<T> elementTye) {
|
||||||
this.body = body;
|
throw new UnsupportedOperationException();
|
||||||
this.bodyElementType = elementTye;
|
|
||||||
this.bodyValue = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -389,15 +382,15 @@ public final class HttpRequestValues {
|
|||||||
Map<String, String> uriVars = (this.uriVars != null ? new HashMap<>(this.uriVars) : Collections.emptyMap());
|
Map<String, String> uriVars = (this.uriVars != null ? new HashMap<>(this.uriVars) : Collections.emptyMap());
|
||||||
|
|
||||||
Object bodyValue = this.bodyValue;
|
Object bodyValue = this.bodyValue;
|
||||||
if (this.multipartBuilder != null) {
|
if (hasParts()) {
|
||||||
Assert.isTrue(bodyValue == null && this.body == null, "Expected body or request parts, not both");
|
Assert.isTrue(!hasBody(), "Expected body or request parts, not both");
|
||||||
bodyValue = this.multipartBuilder.build();
|
bodyValue = buildMultipartBody();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!CollectionUtils.isEmpty(this.requestParams)) {
|
if (!CollectionUtils.isEmpty(this.requestParams)) {
|
||||||
if (hasContentType(MediaType.APPLICATION_FORM_URLENCODED)) {
|
if (hasFormDataContentType()) {
|
||||||
Assert.isTrue(this.multipartBuilder == null, "Cannot add parts to form data request");
|
Assert.isTrue(!hasParts(), "Request parts not expected for a form data request");
|
||||||
Assert.isTrue(bodyValue == null && this.body == null, "Cannot set body of form data request");
|
Assert.isTrue(!hasBody(), "Body not expected for a form data request");
|
||||||
bodyValue = new LinkedMultiValueMap<>(this.requestParams);
|
bodyValue = new LinkedMultiValueMap<>(this.requestParams);
|
||||||
}
|
}
|
||||||
else if (uri != null) {
|
else if (uri != null) {
|
||||||
@@ -426,13 +419,26 @@ public final class HttpRequestValues {
|
|||||||
Map<String, Object> attributes = (this.attributes != null ?
|
Map<String, Object> attributes = (this.attributes != null ?
|
||||||
new HashMap<>(this.attributes) : Collections.emptyMap());
|
new HashMap<>(this.attributes) : Collections.emptyMap());
|
||||||
|
|
||||||
return new HttpRequestValues(
|
return createRequestValues(
|
||||||
this.httpMethod, uri, uriTemplate, uriVars, headers, cookies, attributes,
|
this.httpMethod, uri, uriTemplate, uriVars, headers, cookies, attributes, bodyValue);
|
||||||
bodyValue, this.body, this.bodyElementType);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean hasContentType(MediaType mediaType) {
|
protected boolean hasParts() {
|
||||||
return (this.headers != null && mediaType.equals(this.headers.getContentType()));
|
return (this.parts != null);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean hasBody() {
|
||||||
|
return (this.bodyValue != null);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Object buildMultipartBody() {
|
||||||
|
Assert.notNull(this.parts, "`parts` is null, was hasParts() not called?");
|
||||||
|
return this.parts;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean hasFormDataContentType() {
|
||||||
|
return (this.headers != null &&
|
||||||
|
MediaType.APPLICATION_FORM_URLENCODED.equals(this.headers.getContentType()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private String appendQueryParams(
|
private String appendQueryParams(
|
||||||
@@ -453,6 +459,15 @@ public final class HttpRequestValues {
|
|||||||
return uriComponentsBuilder.build().toUriString();
|
return uriComponentsBuilder.build().toUriString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected HttpRequestValues createRequestValues(
|
||||||
|
@Nullable HttpMethod httpMethod,
|
||||||
|
@Nullable URI uri, @Nullable String uriTemplate, Map<String, String> uriVars,
|
||||||
|
HttpHeaders headers, MultiValueMap<String, String> cookies, Map<String, Object> attributes,
|
||||||
|
@Nullable Object bodyValue) {
|
||||||
|
|
||||||
|
return new HttpRequestValues(
|
||||||
|
this.httpMethod, uri, uriTemplate, uriVars, headers, cookies, attributes, bodyValue);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import java.util.Arrays;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
import org.reactivestreams.Publisher;
|
import org.reactivestreams.Publisher;
|
||||||
import reactor.core.publisher.Flux;
|
import reactor.core.publisher.Flux;
|
||||||
@@ -81,13 +82,16 @@ final class HttpServiceMethod {
|
|||||||
this.parameters = initMethodParameters(method);
|
this.parameters = initMethodParameters(method);
|
||||||
this.argumentResolvers = argumentResolvers;
|
this.argumentResolvers = argumentResolvers;
|
||||||
|
|
||||||
this.requestValuesInitializer =
|
boolean isReactorAdapter = (REACTOR_PRESENT && adapter instanceof ReactorHttpExchangeAdapter);
|
||||||
HttpRequestValuesInitializer.create(method, containingClass, embeddedValueResolver);
|
|
||||||
|
|
||||||
this.responseFunction =
|
this.requestValuesInitializer =
|
||||||
(REACTOR_PRESENT && adapter instanceof ReactorHttpExchangeAdapter reactorAdapter ?
|
HttpRequestValuesInitializer.create(
|
||||||
ReactorExchangeResponseFunction.create(reactorAdapter, method) :
|
method, containingClass, embeddedValueResolver,
|
||||||
ExchangeResponseFunction.create(adapter, method));
|
(isReactorAdapter ? ReactiveHttpRequestValues::builder : HttpRequestValues::builder));
|
||||||
|
|
||||||
|
this.responseFunction = (isReactorAdapter ?
|
||||||
|
ReactorExchangeResponseFunction.create((ReactorHttpExchangeAdapter) adapter, method) :
|
||||||
|
ExchangeResponseFunction.create(adapter, method));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static MethodParameter[] initMethodParameters(Method method) {
|
private static MethodParameter[] initMethodParameters(Method method) {
|
||||||
@@ -147,20 +151,11 @@ final class HttpServiceMethod {
|
|||||||
*/
|
*/
|
||||||
private record HttpRequestValuesInitializer(
|
private record HttpRequestValuesInitializer(
|
||||||
@Nullable HttpMethod httpMethod, @Nullable String url,
|
@Nullable HttpMethod httpMethod, @Nullable String url,
|
||||||
@Nullable MediaType contentType, @Nullable List<MediaType> acceptMediaTypes) {
|
@Nullable MediaType contentType, @Nullable List<MediaType> acceptMediaTypes,
|
||||||
|
Supplier<HttpRequestValues.Builder> requestValuesSupplier) {
|
||||||
private HttpRequestValuesInitializer(
|
|
||||||
HttpMethod httpMethod, @Nullable String url,
|
|
||||||
@Nullable MediaType contentType, @Nullable List<MediaType> acceptMediaTypes) {
|
|
||||||
|
|
||||||
this.url = url;
|
|
||||||
this.httpMethod = httpMethod;
|
|
||||||
this.contentType = contentType;
|
|
||||||
this.acceptMediaTypes = acceptMediaTypes;
|
|
||||||
}
|
|
||||||
|
|
||||||
public HttpRequestValues.Builder initializeRequestValuesBuilder() {
|
public HttpRequestValues.Builder initializeRequestValuesBuilder() {
|
||||||
HttpRequestValues.Builder requestValues = HttpRequestValues.builder();
|
HttpRequestValues.Builder requestValues = this.requestValuesSupplier.get();
|
||||||
if (this.httpMethod != null) {
|
if (this.httpMethod != null) {
|
||||||
requestValues.setHttpMethod(this.httpMethod);
|
requestValues.setHttpMethod(this.httpMethod);
|
||||||
}
|
}
|
||||||
@@ -181,7 +176,8 @@ final class HttpServiceMethod {
|
|||||||
* Introspect the method and create the request factory for it.
|
* Introspect the method and create the request factory for it.
|
||||||
*/
|
*/
|
||||||
public static HttpRequestValuesInitializer create(
|
public static HttpRequestValuesInitializer create(
|
||||||
Method method, Class<?> containingClass, @Nullable StringValueResolver embeddedValueResolver) {
|
Method method, Class<?> containingClass, @Nullable StringValueResolver embeddedValueResolver,
|
||||||
|
Supplier<HttpRequestValues.Builder> requestValuesSupplier) {
|
||||||
|
|
||||||
HttpExchange annot1 = AnnotatedElementUtils.findMergedAnnotation(containingClass, HttpExchange.class);
|
HttpExchange annot1 = AnnotatedElementUtils.findMergedAnnotation(containingClass, HttpExchange.class);
|
||||||
HttpExchange annot2 = AnnotatedElementUtils.findMergedAnnotation(method, HttpExchange.class);
|
HttpExchange annot2 = AnnotatedElementUtils.findMergedAnnotation(method, HttpExchange.class);
|
||||||
@@ -193,7 +189,8 @@ final class HttpServiceMethod {
|
|||||||
MediaType contentType = initContentType(annot1, annot2);
|
MediaType contentType = initContentType(annot1, annot2);
|
||||||
List<MediaType> acceptableMediaTypes = initAccept(annot1, annot2);
|
List<MediaType> acceptableMediaTypes = initAccept(annot1, annot2);
|
||||||
|
|
||||||
return new HttpRequestValuesInitializer(httpMethod, url, contentType, acceptableMediaTypes);
|
return new HttpRequestValuesInitializer(
|
||||||
|
httpMethod, url, contentType, acceptableMediaTypes, requestValuesSupplier);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
|
|||||||
@@ -0,0 +1,275 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2002-2023 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.springframework.web.service.invoker;
|
||||||
|
|
||||||
|
import java.net.URI;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.reactivestreams.Publisher;
|
||||||
|
|
||||||
|
import org.springframework.core.ParameterizedTypeReference;
|
||||||
|
import org.springframework.core.ResolvableType;
|
||||||
|
import org.springframework.http.HttpHeaders;
|
||||||
|
import org.springframework.http.HttpMethod;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.http.client.MultipartBodyBuilder;
|
||||||
|
import org.springframework.lang.Nullable;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
import org.springframework.util.MultiValueMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link HttpRequestValues} extension for use with {@link ReactorHttpExchangeAdapter}.
|
||||||
|
*
|
||||||
|
* @author Rossen Stoyanchev
|
||||||
|
* @since 6.1
|
||||||
|
*/
|
||||||
|
public final class ReactiveHttpRequestValues extends HttpRequestValues {
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private final Publisher<?> body;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private final ParameterizedTypeReference<?> bodyElementType;
|
||||||
|
|
||||||
|
|
||||||
|
private ReactiveHttpRequestValues(
|
||||||
|
@Nullable HttpMethod httpMethod,
|
||||||
|
@Nullable URI uri, @Nullable String uriTemplate, Map<String, String> uriVariables,
|
||||||
|
HttpHeaders headers, MultiValueMap<String, String> cookies, Map<String, Object> attributes,
|
||||||
|
@Nullable Object bodyValue, @Nullable Publisher<?> body, @Nullable ParameterizedTypeReference<?> elementType) {
|
||||||
|
|
||||||
|
super(httpMethod, uri, uriTemplate, uriVariables, headers, cookies, attributes, bodyValue);
|
||||||
|
|
||||||
|
this.body = body;
|
||||||
|
this.bodyElementType = elementType;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a {@link Publisher} that will produce for the request body.
|
||||||
|
* <p>This is mutually exclusive with {@link #getBodyValue()}.
|
||||||
|
* Only one of the two or neither is set.
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public Publisher<?> getBodyPublisher() {
|
||||||
|
return this.body;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the element type for a {@linkplain #getBodyPublisher() Publisher body}.
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public ParameterizedTypeReference<?> getBodyPublisherElementType() {
|
||||||
|
return this.bodyElementType;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the request body as a Publisher.
|
||||||
|
* <p>This is mutually exclusive with {@link #getBodyValue()}.
|
||||||
|
* Only one of the two or neither is set.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("removal")
|
||||||
|
@Nullable
|
||||||
|
public Publisher<?> getBody() {
|
||||||
|
return getBodyPublisher();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the element type for a {@linkplain #getBodyPublisher() Publisher body}.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("removal")
|
||||||
|
@Nullable
|
||||||
|
public ParameterizedTypeReference<?> getBodyElementType() {
|
||||||
|
return getBodyPublisherElementType();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static Builder builder() {
|
||||||
|
return new Builder();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builder for {@link ReactiveHttpRequestValues}.
|
||||||
|
*/
|
||||||
|
public final static class Builder extends HttpRequestValues.Builder {
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private MultipartBodyBuilder multipartBuilder;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private Publisher<?> body;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private ParameterizedTypeReference<?> bodyElementType;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Builder setHttpMethod(HttpMethod httpMethod) {
|
||||||
|
super.setHttpMethod(httpMethod);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Builder setUri(URI uri) {
|
||||||
|
super.setUri(uri);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Builder setUriTemplate(String uriTemplate) {
|
||||||
|
super.setUriTemplate(uriTemplate);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Builder setUriVariable(String name, String value) {
|
||||||
|
super.setUriVariable(name, value);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Builder setAccept(List<MediaType> acceptableMediaTypes) {
|
||||||
|
super.setAccept(acceptableMediaTypes);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Builder setContentType(MediaType contentType) {
|
||||||
|
super.setContentType(contentType);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Builder addHeader(String headerName, String... headerValues) {
|
||||||
|
super.addHeader(headerName, headerValues);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Builder addCookie(String name, String... values) {
|
||||||
|
super.addCookie(name, values);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Builder addRequestParameter(String name, String... values) {
|
||||||
|
super.addRequestParameter(name, values);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Builder addAttribute(String name, Object value) {
|
||||||
|
super.addAttribute(name, value);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a part to a multipart request. The part value may be as described
|
||||||
|
* in {@link MultipartBodyBuilder#part(String, Object)}.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Builder addRequestPart(String name, Object part) {
|
||||||
|
this.multipartBuilder = (this.multipartBuilder != null ? this.multipartBuilder : new MultipartBodyBuilder());
|
||||||
|
this.multipartBuilder.part(name, part);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Variant of {@link #addRequestPart(String, Object)} that allows the
|
||||||
|
* part value to be produced by a {@link Publisher}.
|
||||||
|
*/
|
||||||
|
public <T, P extends Publisher<T>> Builder addRequestPartPublisher(
|
||||||
|
String name, P publisher, ParameterizedTypeReference<T> elementTye) {
|
||||||
|
|
||||||
|
this.multipartBuilder = (this.multipartBuilder != null ? this.multipartBuilder : new MultipartBodyBuilder());
|
||||||
|
this.multipartBuilder.asyncPart(name, publisher, elementTye);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("removal")
|
||||||
|
@Override
|
||||||
|
public <T, P extends Publisher<T>> Builder addRequestPart(String name, P publisher, ResolvableType type) {
|
||||||
|
return addRequestPartPublisher(name, publisher, ParameterizedTypeReference.forType(type.getType()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
* <p>This is mutually exclusive with, and resets any previously set
|
||||||
|
* {@linkplain #setBodyPublisher(Publisher, ParameterizedTypeReference)}.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void setBodyValue(Object bodyValue) {
|
||||||
|
super.setBodyValue(bodyValue);
|
||||||
|
this.body = null;
|
||||||
|
this.bodyElementType = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the request body as a Reactive Streams Publisher.
|
||||||
|
* <p>This is mutually exclusive with, and resets any previously set
|
||||||
|
* {@linkplain #setBodyValue(Object) body value}.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("DataFlowIssue")
|
||||||
|
public <T, P extends Publisher<T>> void setBodyPublisher(P body, ParameterizedTypeReference<T> elementTye) {
|
||||||
|
this.body = body;
|
||||||
|
this.bodyElementType = elementTye;
|
||||||
|
super.setBodyValue(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("removal")
|
||||||
|
@Override
|
||||||
|
public <T, P extends Publisher<T>> void setBody(P body, ParameterizedTypeReference<T> elementTye) {
|
||||||
|
setBodyPublisher(body, elementTye);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ReactiveHttpRequestValues build() {
|
||||||
|
return (ReactiveHttpRequestValues) super.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean hasParts() {
|
||||||
|
return (this.multipartBuilder != null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean hasBody() {
|
||||||
|
return (super.hasBody() || this.body != null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Object buildMultipartBody() {
|
||||||
|
Assert.notNull(this.multipartBuilder, "`multipartBuilder` is null, was hasParts() not called?");
|
||||||
|
return this.multipartBuilder.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected ReactiveHttpRequestValues createRequestValues(
|
||||||
|
@Nullable HttpMethod httpMethod,
|
||||||
|
@Nullable URI uri, @Nullable String uriTemplate, Map<String, String> uriVars,
|
||||||
|
HttpHeaders headers, MultiValueMap<String, String> cookies, Map<String, Object> attributes,
|
||||||
|
@Nullable Object bodyValue) {
|
||||||
|
|
||||||
|
return new ReactiveHttpRequestValues(
|
||||||
|
httpMethod, uri, uriTemplate, uriVars, headers, cookies, attributes,
|
||||||
|
bodyValue, this.body, this.bodyElementType);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -78,9 +78,14 @@ public class RequestBodyArgumentResolver implements HttpServiceArgumentResolver
|
|||||||
Assert.isTrue(!adapter.isNoValue(), message);
|
Assert.isTrue(!adapter.isNoValue(), message);
|
||||||
Assert.isTrue(nestedParameter.getNestedParameterType() != Void.class, message);
|
Assert.isTrue(nestedParameter.getNestedParameterType() != Void.class, message);
|
||||||
|
|
||||||
requestValues.setBody(
|
if (requestValues instanceof ReactiveHttpRequestValues.Builder reactiveRequestValues) {
|
||||||
adapter.toPublisher(argument),
|
reactiveRequestValues.setBodyPublisher(
|
||||||
ParameterizedTypeReference.forType(nestedParameter.getNestedGenericParameterType()));
|
adapter.toPublisher(argument), asParameterizedTypeRef(nestedParameter));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw new IllegalStateException(
|
||||||
|
"RequestBody with a reactive type is only supported with reactive client");
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -93,4 +98,8 @@ public class RequestBodyArgumentResolver implements HttpServiceArgumentResolver
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static ParameterizedTypeReference<Object> asParameterizedTypeRef(MethodParameter nestedParam) {
|
||||||
|
return ParameterizedTypeReference.forType(nestedParam.getNestedGenericParameterType());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,9 +19,9 @@ package org.springframework.web.service.invoker;
|
|||||||
import org.reactivestreams.Publisher;
|
import org.reactivestreams.Publisher;
|
||||||
|
|
||||||
import org.springframework.core.MethodParameter;
|
import org.springframework.core.MethodParameter;
|
||||||
|
import org.springframework.core.ParameterizedTypeReference;
|
||||||
import org.springframework.core.ReactiveAdapter;
|
import org.springframework.core.ReactiveAdapter;
|
||||||
import org.springframework.core.ReactiveAdapterRegistry;
|
import org.springframework.core.ReactiveAdapterRegistry;
|
||||||
import org.springframework.core.ResolvableType;
|
|
||||||
import org.springframework.http.HttpEntity;
|
import org.springframework.http.HttpEntity;
|
||||||
import org.springframework.http.codec.multipart.Part;
|
import org.springframework.http.codec.multipart.Part;
|
||||||
import org.springframework.lang.Nullable;
|
import org.springframework.lang.Nullable;
|
||||||
@@ -89,9 +89,20 @@ public class RequestPartArgumentResolver extends AbstractNamedValueArgumentResol
|
|||||||
Class<?> type = parameter.getParameterType();
|
Class<?> type = parameter.getParameterType();
|
||||||
ReactiveAdapter adapter = this.reactiveAdapterRegistry.getAdapter(type);
|
ReactiveAdapter adapter = this.reactiveAdapterRegistry.getAdapter(type);
|
||||||
if (adapter != null) {
|
if (adapter != null) {
|
||||||
Assert.isTrue(!adapter.isNoValue(), "Expected publisher that produces a value");
|
MethodParameter nestedParameter = parameter.nested();
|
||||||
Publisher<?> publisher = adapter.toPublisher(value);
|
|
||||||
requestValues.addRequestPart(name, publisher, ResolvableType.forMethodParameter(parameter.nested()));
|
String message = "Async type for @RequestPart should produce value(s)";
|
||||||
|
Assert.isTrue(!adapter.isNoValue(), message);
|
||||||
|
Assert.isTrue(nestedParameter.getNestedParameterType() != Void.class, message);
|
||||||
|
|
||||||
|
if (requestValues instanceof ReactiveHttpRequestValues.Builder reactiveValues) {
|
||||||
|
reactiveValues.addRequestPartPublisher(
|
||||||
|
name, adapter.toPublisher(value), asParameterizedTypeRef(nestedParameter));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw new IllegalStateException(
|
||||||
|
"RequestPart with a reactive type is only supported with reactive client");
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -99,4 +110,8 @@ public class RequestPartArgumentResolver extends AbstractNamedValueArgumentResol
|
|||||||
requestValues.addRequestPart(name, value);
|
requestValues.addRequestPart(name, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static ParameterizedTypeReference<Object> asParameterizedTypeRef(MethodParameter nestedParam) {
|
||||||
|
return ParameterizedTypeReference.forType(nestedParam.getNestedGenericParameterType());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -125,9 +125,9 @@ class HttpRequestValuesTests {
|
|||||||
.build();
|
.build();
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
MultiValueMap<String, HttpEntity<?>> map = (MultiValueMap<String, HttpEntity<?>>) requestValues.getBodyValue();
|
MultiValueMap<String, Object> map = (MultiValueMap<String, Object>) requestValues.getBodyValue();
|
||||||
assertThat(map).hasSize(2);
|
assertThat(map).hasSize(2);
|
||||||
assertThat(map.getFirst("form field").getBody()).isEqualTo("form value");
|
assertThat(map.getFirst("form field")).isEqualTo("form value");
|
||||||
assertThat(map.getFirst("entity")).isEqualTo(entity);
|
assertThat(map.getFirst("entity")).isEqualTo(entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -146,9 +146,9 @@ class HttpRequestValuesTests {
|
|||||||
assertThat(uriTemplate).isEqualTo("/path?{queryParam0}={queryParam0[0]}");
|
assertThat(uriTemplate).isEqualTo("/path?{queryParam0}={queryParam0[0]}");
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
MultiValueMap<String, HttpEntity<?>> map = (MultiValueMap<String, HttpEntity<?>>) requestValues.getBodyValue();
|
MultiValueMap<String, Object> map = (MultiValueMap<String, Object>) requestValues.getBodyValue();
|
||||||
assertThat(map).hasSize(1);
|
assertThat(map).hasSize(1);
|
||||||
assertThat(map.getFirst("form field").getBody()).isEqualTo("form value");
|
assertThat(map.getFirst("form field")).isEqualTo("form value");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import org.reactivestreams.Publisher;
|
|||||||
import reactor.core.publisher.Mono;
|
import reactor.core.publisher.Mono;
|
||||||
|
|
||||||
import org.springframework.core.ParameterizedTypeReference;
|
import org.springframework.core.ParameterizedTypeReference;
|
||||||
|
import org.springframework.lang.Nullable;
|
||||||
import org.springframework.web.bind.annotation.RequestBody;
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
import org.springframework.web.service.annotation.GetExchange;
|
import org.springframework.web.service.annotation.GetExchange;
|
||||||
|
|
||||||
@@ -32,12 +33,11 @@ import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Unit tests for {@link RequestBodyArgumentResolver}.
|
* Unit tests for {@link RequestBodyArgumentResolver}.
|
||||||
*
|
|
||||||
* @author Rossen Stoyanchev
|
* @author Rossen Stoyanchev
|
||||||
*/
|
*/
|
||||||
class RequestBodyArgumentResolverTests {
|
class RequestBodyArgumentResolverTests {
|
||||||
|
|
||||||
private final TestExchangeAdapter client = new TestExchangeAdapter();
|
private final TestReactorExchangeAdapter client = new TestReactorExchangeAdapter();
|
||||||
|
|
||||||
private final Service service =
|
private final Service service =
|
||||||
HttpServiceProxyFactory.builderFor(this.client).build().createClient(Service.class);
|
HttpServiceProxyFactory.builderFor(this.client).build().createClient(Service.class);
|
||||||
@@ -48,8 +48,8 @@ class RequestBodyArgumentResolverTests {
|
|||||||
String body = "bodyValue";
|
String body = "bodyValue";
|
||||||
this.service.execute(body);
|
this.service.execute(body);
|
||||||
|
|
||||||
assertThat(getRequestValues().getBodyValue()).isEqualTo(body);
|
assertThat(getBodyValue()).isEqualTo(body);
|
||||||
assertThat(getRequestValues().getBody()).isNull();
|
assertThat(getPublisherBody()).isNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -57,9 +57,9 @@ class RequestBodyArgumentResolverTests {
|
|||||||
Mono<String> bodyMono = Mono.just("bodyValue");
|
Mono<String> bodyMono = Mono.just("bodyValue");
|
||||||
this.service.executeMono(bodyMono);
|
this.service.executeMono(bodyMono);
|
||||||
|
|
||||||
assertThat(getRequestValues().getBodyValue()).isNull();
|
assertThat(getBodyValue()).isNull();
|
||||||
assertThat(getRequestValues().getBody()).isSameAs(bodyMono);
|
assertThat(getPublisherBody()).isSameAs(bodyMono);
|
||||||
assertThat(getRequestValues().getBodyElementType()).isEqualTo(new ParameterizedTypeReference<String>() {});
|
assertThat(getBodyElementType()).isEqualTo(new ParameterizedTypeReference<String>() {});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -68,10 +68,10 @@ class RequestBodyArgumentResolverTests {
|
|||||||
String bodyValue = "bodyValue";
|
String bodyValue = "bodyValue";
|
||||||
this.service.executeSingle(Single.just(bodyValue));
|
this.service.executeSingle(Single.just(bodyValue));
|
||||||
|
|
||||||
assertThat(getRequestValues().getBodyValue()).isNull();
|
assertThat(getBodyValue()).isNull();
|
||||||
assertThat(getRequestValues().getBodyElementType()).isEqualTo(new ParameterizedTypeReference<String>() {});
|
assertThat(getBodyElementType()).isEqualTo(new ParameterizedTypeReference<String>() {});
|
||||||
|
|
||||||
Publisher<?> body = getRequestValues().getBody();
|
Publisher<?> body = getPublisherBody();
|
||||||
assertThat(body).isNotNull();
|
assertThat(body).isNotNull();
|
||||||
assertThat(((Mono<String>) body).block()).isEqualTo(bodyValue);
|
assertThat(((Mono<String>) body).block()).isEqualTo(bodyValue);
|
||||||
}
|
}
|
||||||
@@ -104,17 +104,32 @@ class RequestBodyArgumentResolverTests {
|
|||||||
void ignoreNull() {
|
void ignoreNull() {
|
||||||
this.service.execute(null);
|
this.service.execute(null);
|
||||||
|
|
||||||
assertThat(getRequestValues().getBodyValue()).isNull();
|
assertThat(getBodyValue()).isNull();
|
||||||
assertThat(getRequestValues().getBody()).isNull();
|
assertThat(getPublisherBody()).isNull();
|
||||||
|
|
||||||
this.service.executeMono(null);
|
this.service.executeMono(null);
|
||||||
|
|
||||||
assertThat(getRequestValues().getBodyValue()).isNull();
|
assertThat(getBodyValue()).isNull();
|
||||||
assertThat(getRequestValues().getBody()).isNull();
|
assertThat(getPublisherBody()).isNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
private HttpRequestValues getRequestValues() {
|
@Nullable
|
||||||
return this.client.getRequestValues();
|
private Object getBodyValue() {
|
||||||
|
return getReactiveRequestValues().getBodyValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private Publisher<?> getPublisherBody() {
|
||||||
|
return getReactiveRequestValues().getBodyPublisher();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private ParameterizedTypeReference<?> getBodyElementType() {
|
||||||
|
return getReactiveRequestValues().getBodyPublisherElementType();
|
||||||
|
}
|
||||||
|
|
||||||
|
private ReactiveHttpRequestValues getReactiveRequestValues() {
|
||||||
|
return (ReactiveHttpRequestValues) this.client.getRequestValues();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
|||||||
*/
|
*/
|
||||||
class RequestPartArgumentResolverTests {
|
class RequestPartArgumentResolverTests {
|
||||||
|
|
||||||
private final TestExchangeAdapter client = new TestExchangeAdapter();
|
private final TestReactorExchangeAdapter client = new TestReactorExchangeAdapter();
|
||||||
|
|
||||||
private final Service service =
|
private final Service service =
|
||||||
HttpServiceProxyFactory.builderFor(this.client).build().createClient(Service.class);
|
HttpServiceProxyFactory.builderFor(this.client).build().createClient(Service.class);
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package org.springframework.web.reactive.function.client.support;
|
package org.springframework.web.reactive.function.client.support;
|
||||||
|
|
||||||
|
import org.reactivestreams.Publisher;
|
||||||
import reactor.core.publisher.Flux;
|
import reactor.core.publisher.Flux;
|
||||||
import reactor.core.publisher.Mono;
|
import reactor.core.publisher.Mono;
|
||||||
|
|
||||||
@@ -28,6 +29,7 @@ import org.springframework.web.reactive.function.client.WebClient;
|
|||||||
import org.springframework.web.service.invoker.AbstractReactorHttpExchangeAdapter;
|
import org.springframework.web.service.invoker.AbstractReactorHttpExchangeAdapter;
|
||||||
import org.springframework.web.service.invoker.HttpRequestValues;
|
import org.springframework.web.service.invoker.HttpRequestValues;
|
||||||
import org.springframework.web.service.invoker.HttpServiceProxyFactory;
|
import org.springframework.web.service.invoker.HttpServiceProxyFactory;
|
||||||
|
import org.springframework.web.service.invoker.ReactiveHttpRequestValues;
|
||||||
import org.springframework.web.service.invoker.ReactorHttpExchangeAdapter;
|
import org.springframework.web.service.invoker.ReactorHttpExchangeAdapter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -119,9 +121,13 @@ public final class WebClientAdapter extends AbstractReactorHttpExchangeAdapter {
|
|||||||
if (requestValues.getBodyValue() != null) {
|
if (requestValues.getBodyValue() != null) {
|
||||||
bodySpec.bodyValue(requestValues.getBodyValue());
|
bodySpec.bodyValue(requestValues.getBodyValue());
|
||||||
}
|
}
|
||||||
else if (requestValues.getBody() != null) {
|
else if (requestValues instanceof ReactiveHttpRequestValues reactiveRequestValues) {
|
||||||
Assert.notNull(requestValues.getBodyElementType(), "Publisher body element type is required");
|
Publisher<?> body = reactiveRequestValues.getBodyPublisher();
|
||||||
bodySpec.body(requestValues.getBody(), requestValues.getBodyElementType());
|
if (body != null) {
|
||||||
|
ParameterizedTypeReference<?> elementType = reactiveRequestValues.getBodyPublisherElementType();
|
||||||
|
Assert.notNull(elementType, "Publisher body element type is required");
|
||||||
|
bodySpec.body(body, elementType);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return bodySpec;
|
return bodySpec;
|
||||||
|
|||||||
Reference in New Issue
Block a user