Refactor HttpRequestSpec to HttpRequestValues
HttpRequestValues is immutable and exposes a builder. See gh-28386
This commit is contained in:
parent
564f8ba7a0
commit
d7ab5b4132
|
@ -33,18 +33,18 @@ import org.springframework.http.ResponseEntity;
|
||||||
*/
|
*/
|
||||||
public interface HttpClientAdapter {
|
public interface HttpClientAdapter {
|
||||||
|
|
||||||
Mono<Void> requestToVoid(HttpRequestSpec spec);
|
Mono<Void> requestToVoid(HttpRequestValues requestValues);
|
||||||
|
|
||||||
Mono<HttpHeaders> requestToHeaders(HttpRequestSpec spec);
|
Mono<HttpHeaders> requestToHeaders(HttpRequestValues requestValues);
|
||||||
|
|
||||||
<T> Mono<T> requestToBody(HttpRequestSpec spec, ParameterizedTypeReference<T> bodyType);
|
<T> Mono<T> requestToBody(HttpRequestValues requestValues, ParameterizedTypeReference<T> bodyType);
|
||||||
|
|
||||||
<T> Flux<T> requestToBodyFlux(HttpRequestSpec spec, ParameterizedTypeReference<T> bodyType);
|
<T> Flux<T> requestToBodyFlux(HttpRequestValues requestValues, ParameterizedTypeReference<T> bodyType);
|
||||||
|
|
||||||
Mono<ResponseEntity<Void>> requestToBodilessEntity(HttpRequestSpec spec);
|
Mono<ResponseEntity<Void>> requestToBodilessEntity(HttpRequestValues requestValues);
|
||||||
|
|
||||||
<T> Mono<ResponseEntity<T>> requestToEntity(HttpRequestSpec spec, ParameterizedTypeReference<T> bodyType);
|
<T> Mono<ResponseEntity<T>> requestToEntity(HttpRequestValues requestValues, ParameterizedTypeReference<T> bodyType);
|
||||||
|
|
||||||
<T> Mono<ResponseEntity<Flux<T>>> requestToEntityFlux(HttpRequestSpec spec, ParameterizedTypeReference<T> bodyType);
|
<T> Mono<ResponseEntity<Flux<T>>> requestToEntityFlux(HttpRequestValues requestValues, ParameterizedTypeReference<T> bodyType);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,7 +38,7 @@ public class HttpMethodArgumentResolver implements HttpServiceArgumentResolver {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void resolve(
|
public void resolve(
|
||||||
@Nullable Object argument, MethodParameter parameter, HttpRequestSpec requestSpec) {
|
@Nullable Object argument, MethodParameter parameter, HttpRequestValues.Builder requestValues) {
|
||||||
|
|
||||||
if (argument == null) {
|
if (argument == null) {
|
||||||
return;
|
return;
|
||||||
|
@ -47,7 +47,7 @@ public class HttpMethodArgumentResolver implements HttpServiceArgumentResolver {
|
||||||
if (logger.isTraceEnabled()) {
|
if (logger.isTraceEnabled()) {
|
||||||
logger.trace("Resolved HTTP method to: " + httpMethod.name());
|
logger.trace("Resolved HTTP method to: " + httpMethod.name());
|
||||||
}
|
}
|
||||||
requestSpec.setHttpMethod(httpMethod);
|
requestValues.setHttpMethod(httpMethod);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,196 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2002-2022 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.ArrayList;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.LinkedHashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import org.reactivestreams.Publisher;
|
|
||||||
|
|
||||||
import org.springframework.core.MethodParameter;
|
|
||||||
import org.springframework.core.ParameterizedTypeReference;
|
|
||||||
import org.springframework.http.HttpHeaders;
|
|
||||||
import org.springframework.http.HttpMethod;
|
|
||||||
import org.springframework.lang.Nullable;
|
|
||||||
import org.springframework.util.Assert;
|
|
||||||
import org.springframework.util.CollectionUtils;
|
|
||||||
import org.springframework.util.LinkedMultiValueMap;
|
|
||||||
import org.springframework.util.MultiValueMap;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Container for HTTP request values extracted from an
|
|
||||||
* {@link org.springframework.web.service.annotation.HttpExchange @HttpExchange}-annotated
|
|
||||||
* method and argument values passed to it. This is then given to
|
|
||||||
* {@link HttpClientAdapter} to adapt to the underlying HTTP client.
|
|
||||||
*
|
|
||||||
* @author Rossen Stoyanchev
|
|
||||||
* @since 6.0
|
|
||||||
*/
|
|
||||||
public class HttpRequestSpec {
|
|
||||||
|
|
||||||
private static final MultiValueMap<String, String> EMPTY_COOKIES_MAP =
|
|
||||||
CollectionUtils.toMultiValueMap(Collections.emptyMap());
|
|
||||||
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private URI uri;
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private String uriTemplate;
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private Map<String, String> uriVariables;
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private List<String> uriVariablesList;
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private HttpMethod httpMethod;
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private HttpHeaders headers;
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private MultiValueMap<String, String> cookies;
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private Object bodyValue;
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private Publisher<?> bodyPublisher;
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private ParameterizedTypeReference<?> bodyPublisherElementType;
|
|
||||||
|
|
||||||
private boolean complete;
|
|
||||||
|
|
||||||
|
|
||||||
public HttpRequestSpec() {
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void setUri(URI uri) {
|
|
||||||
checkComplete();
|
|
||||||
this.uri = uri;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
public URI getUri() {
|
|
||||||
return this.uri;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setUriTemplate(String uriTemplate) {
|
|
||||||
checkComplete();
|
|
||||||
this.uriTemplate = uriTemplate;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
public String getUriTemplate() {
|
|
||||||
return this.uriTemplate;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Map<String, String> getUriVariables() {
|
|
||||||
this.uriVariables = (this.uriVariables != null ? this.uriVariables : new LinkedHashMap<>());
|
|
||||||
return this.uriVariables;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<String> getUriVariableValues() {
|
|
||||||
this.uriVariablesList = (this.uriVariablesList != null ? this.uriVariablesList : new ArrayList<>());
|
|
||||||
return this.uriVariablesList;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setHttpMethod(HttpMethod httpMethod) {
|
|
||||||
checkComplete();
|
|
||||||
this.httpMethod = httpMethod;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
public HttpMethod getHttpMethod() {
|
|
||||||
return this.httpMethod;
|
|
||||||
}
|
|
||||||
|
|
||||||
public HttpMethod getHttpMethodRequired() {
|
|
||||||
Assert.notNull(this.httpMethod, "No HttpMethod");
|
|
||||||
return this.httpMethod;
|
|
||||||
}
|
|
||||||
|
|
||||||
public HttpHeaders getHeaders() {
|
|
||||||
this.headers = (this.headers != null ? this.headers : new HttpHeaders());
|
|
||||||
return this.headers;
|
|
||||||
}
|
|
||||||
|
|
||||||
public MultiValueMap<String, String> getCookies() {
|
|
||||||
this.cookies = (this.cookies != null ? this.cookies : new LinkedMultiValueMap<>());
|
|
||||||
return this.cookies;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setBodyValue(Object bodyValue) {
|
|
||||||
checkComplete();
|
|
||||||
this.bodyValue = bodyValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
public Object getBodyValue() {
|
|
||||||
return this.bodyValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
public <T, P extends Publisher<T>> void setBodyPublisher(Publisher<P> bodyPublisher, MethodParameter parameter) {
|
|
||||||
checkComplete();
|
|
||||||
// Adapt to Mono/Flux and nest MethodParameter for element type
|
|
||||||
this.bodyPublisher = bodyPublisher;
|
|
||||||
this.bodyPublisherElementType = ParameterizedTypeReference.forType(parameter.nested().getGenericParameterType());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
public Publisher<?> getBodyPublisher() {
|
|
||||||
return this.bodyPublisher;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ParameterizedTypeReference<?> getBodyPublisherElementType() {
|
|
||||||
Assert.state(this.bodyPublisherElementType != null, "No body Publisher");
|
|
||||||
return this.bodyPublisherElementType;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void checkComplete() {
|
|
||||||
Assert.isTrue(!this.complete, "setComplete already called");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void setComplete() {
|
|
||||||
|
|
||||||
this.complete = true;
|
|
||||||
|
|
||||||
this.uriVariables = (this.uriVariables != null ?
|
|
||||||
Collections.unmodifiableMap(this.uriVariables) : Collections.emptyMap());
|
|
||||||
|
|
||||||
this.uriVariablesList = (this.uriVariablesList != null ?
|
|
||||||
Collections.unmodifiableList(this.uriVariablesList) : Collections.emptyList());
|
|
||||||
|
|
||||||
this.headers = (this.headers != null ?
|
|
||||||
HttpHeaders.readOnlyHttpHeaders(this.headers) : HttpHeaders.EMPTY);
|
|
||||||
|
|
||||||
this.cookies = (this.cookies != null ?
|
|
||||||
CollectionUtils.unmodifiableMultiValueMap(this.cookies) : EMPTY_COOKIES_MAP);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -0,0 +1,337 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2002-2022 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.Collections;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.reactivestreams.Publisher;
|
||||||
|
|
||||||
|
import org.springframework.core.ParameterizedTypeReference;
|
||||||
|
import org.springframework.http.HttpHeaders;
|
||||||
|
import org.springframework.http.HttpMethod;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.lang.Nullable;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
import org.springframework.util.CollectionUtils;
|
||||||
|
import org.springframework.util.LinkedMultiValueMap;
|
||||||
|
import org.springframework.util.MultiValueMap;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Container for HTTP request values extracted from an
|
||||||
|
* {@link org.springframework.web.service.annotation.HttpExchange @HttpExchange}-annotated
|
||||||
|
* method and argument values passed to it. This is then given to
|
||||||
|
* {@link HttpClientAdapter} to adapt to the underlying HTTP client.
|
||||||
|
*
|
||||||
|
* @author Rossen Stoyanchev
|
||||||
|
* @since 6.0
|
||||||
|
*/
|
||||||
|
public final class HttpRequestValues {
|
||||||
|
|
||||||
|
private static final MultiValueMap<String, String> EMPTY_COOKIES_MAP =
|
||||||
|
CollectionUtils.toMultiValueMap(Collections.emptyMap());
|
||||||
|
|
||||||
|
|
||||||
|
private final HttpMethod httpMethod;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private final URI uri;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private final String uriTemplate;
|
||||||
|
|
||||||
|
private final Map<String, String> uriVariables;
|
||||||
|
|
||||||
|
private final HttpHeaders headers;
|
||||||
|
|
||||||
|
private final MultiValueMap<String, String> cookies;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private final Object bodyValue;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private final Publisher<?> body;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private final ParameterizedTypeReference<?> bodyElementType;
|
||||||
|
|
||||||
|
|
||||||
|
private HttpRequestValues(HttpMethod httpMethod, @Nullable URI uri,
|
||||||
|
@Nullable String uriTemplate, @Nullable Map<String, String> uriVariables,
|
||||||
|
@Nullable HttpHeaders headers, @Nullable MultiValueMap<String, String> cookies,
|
||||||
|
@Nullable Object bodyValue,
|
||||||
|
@Nullable Publisher<?> body,
|
||||||
|
@Nullable ParameterizedTypeReference<?> bodyElementType) {
|
||||||
|
|
||||||
|
Assert.isTrue(uri == null || uriTemplate == null, "Expected either URI or URI template, not both");
|
||||||
|
|
||||||
|
this.httpMethod = httpMethod;
|
||||||
|
this.uri = uri;
|
||||||
|
this.uriTemplate = (uri != null || uriTemplate != null ? uriTemplate : "");
|
||||||
|
this.uriVariables = (uriVariables != null ? uriVariables : Collections.emptyMap());
|
||||||
|
this.headers = (headers != null ? headers : HttpHeaders.EMPTY);
|
||||||
|
this.cookies = (cookies != null ? cookies : EMPTY_COOKIES_MAP);
|
||||||
|
this.bodyValue = bodyValue;
|
||||||
|
this.body = body;
|
||||||
|
this.bodyElementType = bodyElementType;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the HTTP method to use for the request.
|
||||||
|
*/
|
||||||
|
public HttpMethod getHttpMethod() {
|
||||||
|
return this.httpMethod;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the full URL to use, if set.
|
||||||
|
* <p>This is mutually exclusive with {@link #getUriTemplate() uriTemplate}.
|
||||||
|
* One of the two has a value but not both.
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public URI getUri() {
|
||||||
|
return this.uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the URL template for the request, if set.
|
||||||
|
* <p>This is mutually exclusive with a {@link #getUri() full URL}.
|
||||||
|
* One of the two has a value but not both.
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public String getUriTemplate() {
|
||||||
|
return this.uriTemplate;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the URL template variables, or an empty map.
|
||||||
|
*/
|
||||||
|
public Map<String, String> getUriVariables() {
|
||||||
|
return this.uriVariables;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the headers for the request, if any.
|
||||||
|
*/
|
||||||
|
public HttpHeaders getHeaders() {
|
||||||
|
return this.headers;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the cookies for the request, if any.
|
||||||
|
*/
|
||||||
|
public MultiValueMap<String, String> getCookies() {
|
||||||
|
return this.cookies;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
public Object getBodyValue() {
|
||||||
|
return this.bodyValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the request body as a Publisher.
|
||||||
|
* <p>This is mutually exclusive with {@link #getBodyValue()}.
|
||||||
|
* Only one of the two or neither is set.
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public Publisher<?> getBody() {
|
||||||
|
return this.body;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the element type for a {@link #getBody() Publisher body}.
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public ParameterizedTypeReference<?> getBodyElementType() {
|
||||||
|
return this.bodyElementType;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static Builder builder(HttpMethod httpMethod) {
|
||||||
|
return new Builder(httpMethod);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builder for {@link HttpRequestValues}.
|
||||||
|
*/
|
||||||
|
public final static class Builder {
|
||||||
|
|
||||||
|
private HttpMethod httpMethod;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private URI uri;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private String uriTemplate;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private Map<String, String> uriVariables;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private HttpHeaders headers;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private MultiValueMap<String, String> cookies;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private Object bodyValue;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private Publisher<?> body;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private ParameterizedTypeReference<?> bodyElementType;
|
||||||
|
|
||||||
|
private Builder(HttpMethod httpMethod) {
|
||||||
|
Assert.notNull(httpMethod, "HttpMethod is required");
|
||||||
|
this.httpMethod = httpMethod;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the HTTP method for the request.
|
||||||
|
*/
|
||||||
|
public Builder setHttpMethod(HttpMethod httpMethod) {
|
||||||
|
Assert.notNull(httpMethod, "HttpMethod is required");
|
||||||
|
this.httpMethod = httpMethod;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the request URL as a full URL.
|
||||||
|
* <p>This is mutually exclusive with, and resets any previously set
|
||||||
|
* {@link #setUriTemplate(String)}.
|
||||||
|
*/
|
||||||
|
public Builder setUri(URI uri) {
|
||||||
|
this.uri = uri;
|
||||||
|
this.uriTemplate = null;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the request URL as a String template.
|
||||||
|
* <p>This is mutually exclusive with, and resets any previously set
|
||||||
|
* {@link #setUri(URI) full URI}.
|
||||||
|
*/
|
||||||
|
public Builder setUriTemplate(String uriTemplate) {
|
||||||
|
this.uriTemplate = uriTemplate;
|
||||||
|
this.uri = null;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a URI variable name-value pair.
|
||||||
|
* <p>This is mutually exclusive with, and resets any previously set
|
||||||
|
* {@link #setUri(URI) full URI}.
|
||||||
|
*/
|
||||||
|
public Builder setUriVariable(String name, String value) {
|
||||||
|
this.uriVariables = (this.uriVariables != null ? this.uriVariables : new LinkedHashMap<>());
|
||||||
|
this.uriVariables.put(name, value);
|
||||||
|
this.uri = null;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the media types for the request {@code Accept} header.
|
||||||
|
*/
|
||||||
|
public Builder setAccept(List<MediaType> acceptableMediaTypes) {
|
||||||
|
initHeaders().setAccept(acceptableMediaTypes);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the media type for the request {@code Content-Type} header.
|
||||||
|
*/
|
||||||
|
public Builder setContentType(MediaType contentType) {
|
||||||
|
initHeaders().setContentType(contentType);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the given header name and values.
|
||||||
|
*/
|
||||||
|
public Builder addHeader(String headerName, String... headerValues) {
|
||||||
|
for (String headerValue : headerValues) {
|
||||||
|
initHeaders().add(headerName, headerValue);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private HttpHeaders initHeaders() {
|
||||||
|
this.headers = (this.headers != null ? this.headers : new HttpHeaders());
|
||||||
|
return this.headers;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the given cookie name and values.
|
||||||
|
*/
|
||||||
|
public Builder addCookie(String name, String... values) {
|
||||||
|
this.cookies = (this.cookies != null ? this.cookies : new LinkedMultiValueMap<>());
|
||||||
|
for (String value : values) {
|
||||||
|
this.cookies.add(name, value);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the request body as a concrete value to be serialized.
|
||||||
|
* <p>This is mutually exclusive with, and resets any previously set
|
||||||
|
* {@link #setBody(Publisher, ParameterizedTypeReference) body Publisher}.
|
||||||
|
*/
|
||||||
|
public void setBodyValue(Object bodyValue) {
|
||||||
|
this.bodyValue = bodyValue;
|
||||||
|
this.body = null;
|
||||||
|
this.bodyElementType = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the request body as a concrete value to be serialized.
|
||||||
|
* <p>This is mutually exclusive with, and resets any previously set
|
||||||
|
* {@link #setBodyValue(Object) body value}.
|
||||||
|
*/
|
||||||
|
public <T, P extends Publisher<T>> void setBody(Publisher<P> body, ParameterizedTypeReference<?> elementTye) {
|
||||||
|
this.body = body;
|
||||||
|
this.bodyElementType = elementTye;
|
||||||
|
this.bodyValue = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builder the {@link HttpRequestValues} instance.
|
||||||
|
*/
|
||||||
|
public HttpRequestValues build() {
|
||||||
|
return new HttpRequestValues(
|
||||||
|
this.httpMethod, this.uri, this.uriTemplate, this.uriVariables,
|
||||||
|
this.headers, this.cookies,
|
||||||
|
this.bodyValue, this.body, this.bodyElementType);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -34,8 +34,8 @@ public interface HttpServiceArgumentResolver {
|
||||||
* Resolve the argument value.
|
* Resolve the argument value.
|
||||||
* @param argument the argument value
|
* @param argument the argument value
|
||||||
* @param parameter the method parameter for the argument
|
* @param parameter the method parameter for the argument
|
||||||
* @param requestSpec container to add HTTP request values to
|
* @param requestValues builder to add HTTP request values to
|
||||||
*/
|
*/
|
||||||
void resolve(@Nullable Object argument, MethodParameter parameter, HttpRequestSpec requestSpec);
|
void resolve(@Nullable Object argument, MethodParameter parameter, HttpRequestValues.Builder requestValues);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,7 +62,7 @@ final class HttpServiceMethod {
|
||||||
|
|
||||||
private final List<HttpServiceArgumentResolver> argumentResolvers;
|
private final List<HttpServiceArgumentResolver> argumentResolvers;
|
||||||
|
|
||||||
private final HttpRequestSpecFactory requestSpecFactory;
|
private final HttpRequestValuesInitializer requestValuesInitializer;
|
||||||
|
|
||||||
private final ResponseFunction responseFunction;
|
private final ResponseFunction responseFunction;
|
||||||
|
|
||||||
|
@ -75,7 +75,7 @@ final class HttpServiceMethod {
|
||||||
this.method = method;
|
this.method = method;
|
||||||
this.parameters = initMethodParameters(method);
|
this.parameters = initMethodParameters(method);
|
||||||
this.argumentResolvers = argumentResolvers;
|
this.argumentResolvers = argumentResolvers;
|
||||||
this.requestSpecFactory = HttpRequestSpecFactory.create(method, containingClass);
|
this.requestValuesInitializer = HttpRequestValuesInitializer.create(method, containingClass);
|
||||||
this.responseFunction = ResponseFunction.create(client, method, reactiveRegistry, blockTimeout);
|
this.responseFunction = ResponseFunction.create(client, method, reactiveRegistry, blockTimeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -96,35 +96,34 @@ final class HttpServiceMethod {
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public Object invoke(Object[] arguments) {
|
public Object invoke(Object[] arguments) {
|
||||||
HttpRequestSpec requestSpec = this.requestSpecFactory.initializeRequestSpec();
|
HttpRequestValues.Builder requestValues = this.requestValuesInitializer.initializeRequestValuesBuilder();
|
||||||
applyArguments(requestSpec, arguments);
|
applyArguments(requestValues, arguments);
|
||||||
requestSpec.setComplete();
|
return this.responseFunction.execute(requestValues.build());
|
||||||
return this.responseFunction.execute(requestSpec);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void applyArguments(HttpRequestSpec requestSpec, Object[] arguments) {
|
private void applyArguments(HttpRequestValues.Builder requestValues, Object[] arguments) {
|
||||||
Assert.isTrue(arguments.length == this.parameters.length, "Method argument mismatch");
|
Assert.isTrue(arguments.length == this.parameters.length, "Method argument mismatch");
|
||||||
for (int i = 0; i < this.parameters.length; i++) {
|
for (int i = 0; i < this.parameters.length; i++) {
|
||||||
Object argumentValue = arguments[i];
|
Object argumentValue = arguments[i];
|
||||||
ParameterNameDiscoverer nameDiscoverer = new DefaultParameterNameDiscoverer();
|
ParameterNameDiscoverer nameDiscoverer = new DefaultParameterNameDiscoverer();
|
||||||
this.parameters[i].initParameterNameDiscovery(nameDiscoverer);
|
this.parameters[i].initParameterNameDiscovery(nameDiscoverer);
|
||||||
for (HttpServiceArgumentResolver resolver : this.argumentResolvers) {
|
for (HttpServiceArgumentResolver resolver : this.argumentResolvers) {
|
||||||
resolver.resolve(argumentValue, this.parameters[i], requestSpec);
|
resolver.resolve(argumentValue, this.parameters[i], requestValues);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Factory for an {@link HttpRequestSpec} with values extracted from
|
* Factory for an {@link HttpRequestValues} with values extracted from
|
||||||
* the type and method-level {@link HttpExchange @HttpRequest} annotations.
|
* the type and method-level {@link HttpExchange @HttpRequest} annotations.
|
||||||
*/
|
*/
|
||||||
private record HttpRequestSpecFactory(
|
private record HttpRequestValuesInitializer(
|
||||||
@Nullable HttpMethod httpMethod, @Nullable String url,
|
HttpMethod httpMethod, @Nullable String url,
|
||||||
@Nullable MediaType contentType, @Nullable List<MediaType> acceptMediaTypes) {
|
@Nullable MediaType contentType, @Nullable List<MediaType> acceptMediaTypes) {
|
||||||
|
|
||||||
private HttpRequestSpecFactory(
|
private HttpRequestValuesInitializer(
|
||||||
@Nullable HttpMethod httpMethod, @Nullable String url,
|
HttpMethod httpMethod, @Nullable String url,
|
||||||
@Nullable MediaType contentType, @Nullable List<MediaType> acceptMediaTypes) {
|
@Nullable MediaType contentType, @Nullable List<MediaType> acceptMediaTypes) {
|
||||||
|
|
||||||
this.url = url;
|
this.url = url;
|
||||||
|
@ -133,28 +132,25 @@ final class HttpServiceMethod {
|
||||||
this.acceptMediaTypes = acceptMediaTypes;
|
this.acceptMediaTypes = acceptMediaTypes;
|
||||||
}
|
}
|
||||||
|
|
||||||
public HttpRequestSpec initializeRequestSpec() {
|
public HttpRequestValues.Builder initializeRequestValuesBuilder() {
|
||||||
HttpRequestSpec requestSpec = new HttpRequestSpec();
|
HttpRequestValues.Builder requestValues = HttpRequestValues.builder(this.httpMethod);
|
||||||
if (this.httpMethod != null) {
|
|
||||||
requestSpec.setHttpMethod(this.httpMethod);
|
|
||||||
}
|
|
||||||
if (this.url != null) {
|
if (this.url != null) {
|
||||||
requestSpec.setUriTemplate(this.url);
|
requestValues.setUriTemplate(this.url);
|
||||||
}
|
}
|
||||||
if (this.contentType != null) {
|
if (this.contentType != null) {
|
||||||
requestSpec.getHeaders().setContentType(this.contentType);
|
requestValues.setContentType(this.contentType);
|
||||||
}
|
}
|
||||||
if (this.acceptMediaTypes != null) {
|
if (this.acceptMediaTypes != null) {
|
||||||
requestSpec.getHeaders().setAccept(this.acceptMediaTypes);
|
requestValues.setAccept(this.acceptMediaTypes);
|
||||||
}
|
}
|
||||||
return requestSpec;
|
return requestValues;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Introspect the method and create the request factory for it.
|
* Introspect the method and create the request factory for it.
|
||||||
*/
|
*/
|
||||||
public static HttpRequestSpecFactory create(Method method, Class<?> containingClass) {
|
public static HttpRequestValuesInitializer create(Method method, Class<?> containingClass) {
|
||||||
|
|
||||||
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);
|
||||||
|
@ -166,11 +162,10 @@ 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 HttpRequestSpecFactory(httpMethod, url, contentType, acceptableMediaTypes);
|
return new HttpRequestValuesInitializer(httpMethod, url, contentType, acceptableMediaTypes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private static HttpMethod initHttpMethod(@Nullable HttpExchange typeAnnot, HttpExchange annot) {
|
private static HttpMethod initHttpMethod(@Nullable HttpExchange typeAnnot, HttpExchange annot) {
|
||||||
|
|
||||||
String value1 = (typeAnnot != null ? typeAnnot.method() : null);
|
String value1 = (typeAnnot != null ? typeAnnot.method() : null);
|
||||||
|
@ -184,7 +179,7 @@ final class HttpServiceMethod {
|
||||||
return HttpMethod.valueOf(value1);
|
return HttpMethod.valueOf(value1);
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
throw new IllegalStateException("HttpMethod is required");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
|
@ -249,12 +244,12 @@ final class HttpServiceMethod {
|
||||||
* return type blocking if necessary.
|
* return type blocking if necessary.
|
||||||
*/
|
*/
|
||||||
private record ResponseFunction(
|
private record ResponseFunction(
|
||||||
Function<HttpRequestSpec, Publisher<?>> responseFunction,
|
Function<HttpRequestValues, Publisher<?>> responseFunction,
|
||||||
@Nullable ReactiveAdapter returnTypeAdapter,
|
@Nullable ReactiveAdapter returnTypeAdapter,
|
||||||
boolean blockForOptional, Duration blockTimeout) {
|
boolean blockForOptional, Duration blockTimeout) {
|
||||||
|
|
||||||
private ResponseFunction(
|
private ResponseFunction(
|
||||||
Function<HttpRequestSpec, Publisher<?>> responseFunction,
|
Function<HttpRequestValues, Publisher<?>> responseFunction,
|
||||||
@Nullable ReactiveAdapter returnTypeAdapter,
|
@Nullable ReactiveAdapter returnTypeAdapter,
|
||||||
boolean blockForOptional, Duration blockTimeout) {
|
boolean blockForOptional, Duration blockTimeout) {
|
||||||
|
|
||||||
|
@ -265,9 +260,9 @@ final class HttpServiceMethod {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public Object execute(HttpRequestSpec requestSpec) {
|
public Object execute(HttpRequestValues requestValues) {
|
||||||
|
|
||||||
Publisher<?> responsePublisher = this.responseFunction.apply(requestSpec);
|
Publisher<?> responsePublisher = this.responseFunction.apply(requestValues);
|
||||||
|
|
||||||
if (this.returnTypeAdapter != null) {
|
if (this.returnTypeAdapter != null) {
|
||||||
return this.returnTypeAdapter.fromPublisher(responsePublisher);
|
return this.returnTypeAdapter.fromPublisher(responsePublisher);
|
||||||
|
@ -293,7 +288,7 @@ final class HttpServiceMethod {
|
||||||
MethodParameter actualParam = (reactiveAdapter != null ? returnParam.nested() : returnParam.nestedIfOptional());
|
MethodParameter actualParam = (reactiveAdapter != null ? returnParam.nested() : returnParam.nestedIfOptional());
|
||||||
Class<?> actualType = actualParam.getNestedParameterType();
|
Class<?> actualType = actualParam.getNestedParameterType();
|
||||||
|
|
||||||
Function<HttpRequestSpec, Publisher<?>> responseFunction;
|
Function<HttpRequestValues, Publisher<?>> responseFunction;
|
||||||
if (actualType.equals(void.class) || actualType.equals(Void.class)) {
|
if (actualType.equals(void.class) || actualType.equals(Void.class)) {
|
||||||
responseFunction = client::requestToVoid;
|
responseFunction = client::requestToVoid;
|
||||||
}
|
}
|
||||||
|
@ -323,7 +318,7 @@ final class HttpServiceMethod {
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("ConstantConditions")
|
@SuppressWarnings("ConstantConditions")
|
||||||
private static Function<HttpRequestSpec, Publisher<?>> initResponseEntityFunction(
|
private static Function<HttpRequestValues, Publisher<?>> initResponseEntityFunction(
|
||||||
HttpClientAdapter client, MethodParameter methodParam, @Nullable ReactiveAdapter reactiveAdapter) {
|
HttpClientAdapter client, MethodParameter methodParam, @Nullable ReactiveAdapter reactiveAdapter) {
|
||||||
|
|
||||||
if (reactiveAdapter == null) {
|
if (reactiveAdapter == null) {
|
||||||
|
@ -349,7 +344,7 @@ final class HttpServiceMethod {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Function<HttpRequestSpec, Publisher<?>> initBodyFunction(
|
private static Function<HttpRequestValues, Publisher<?>> initBodyFunction(
|
||||||
HttpClientAdapter client, MethodParameter methodParam, @Nullable ReactiveAdapter reactiveAdapter) {
|
HttpClientAdapter client, MethodParameter methodParam, @Nullable ReactiveAdapter reactiveAdapter) {
|
||||||
|
|
||||||
ParameterizedTypeReference<?> bodyType =
|
ParameterizedTypeReference<?> bodyType =
|
||||||
|
|
|
@ -56,7 +56,7 @@ public class PathVariableArgumentResolver implements HttpServiceArgumentResolver
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
@Override
|
@Override
|
||||||
public void resolve(
|
public void resolve(
|
||||||
@Nullable Object argument, MethodParameter parameter, HttpRequestSpec requestSpec) {
|
@Nullable Object argument, MethodParameter parameter, HttpRequestValues.Builder requestValues) {
|
||||||
|
|
||||||
PathVariable annotation = parameter.getParameterAnnotation(PathVariable.class);
|
PathVariable annotation = parameter.getParameterAnnotation(PathVariable.class);
|
||||||
if (annotation == null) {
|
if (annotation == null) {
|
||||||
|
@ -67,38 +67,38 @@ public class PathVariableArgumentResolver implements HttpServiceArgumentResolver
|
||||||
if (argument != null) {
|
if (argument != null) {
|
||||||
Assert.isInstanceOf(Map.class, argument);
|
Assert.isInstanceOf(Map.class, argument);
|
||||||
((Map<String, ?>) argument).forEach((key, value) ->
|
((Map<String, ?>) argument).forEach((key, value) ->
|
||||||
addUriParameter(key, value, annotation.required(), requestSpec));
|
addUriParameter(key, value, annotation.required(), requestValues));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
String name = StringUtils.hasText(annotation.value()) ? annotation.value() : annotation.name();
|
String name = StringUtils.hasText(annotation.value()) ? annotation.value() : annotation.name();
|
||||||
name = StringUtils.hasText(name) ? name : parameter.getParameterName();
|
name = StringUtils.hasText(name) ? name : parameter.getParameterName();
|
||||||
Assert.notNull(name, "Failed to determine path variable name for parameter: " + parameter);
|
Assert.notNull(name, "Failed to determine path variable name for parameter: " + parameter);
|
||||||
addUriParameter(name, argument, annotation.required(), requestSpec);
|
addUriParameter(name, argument, annotation.required(), requestValues);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addUriParameter(
|
private void addUriParameter(
|
||||||
String name, @Nullable Object value, boolean required, HttpRequestSpec requestSpec) {
|
String name, @Nullable Object value, boolean required, HttpRequestValues.Builder requestValues) {
|
||||||
|
|
||||||
if (value instanceof Optional) {
|
if (value instanceof Optional) {
|
||||||
value = ((Optional<?>) value).orElse(null);
|
value = ((Optional<?>) value).orElse(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!(value instanceof String)) {
|
||||||
|
value = this.conversionService.convert(value, String.class);
|
||||||
|
}
|
||||||
|
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
Assert.isTrue(!required, "Missing required path variable '" + name + "'");
|
Assert.isTrue(!required, "Missing required path variable '" + name + "'");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(value instanceof String)) {
|
|
||||||
value = this.conversionService.convert(value, String.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (logger.isTraceEnabled()) {
|
if (logger.isTraceEnabled()) {
|
||||||
logger.trace("Resolved path variable '" + name + "' to " + value);
|
logger.trace("Resolved path variable '" + name + "' to " + value);
|
||||||
}
|
}
|
||||||
|
|
||||||
requestSpec.getUriVariables().put(name, (String) value);
|
requestValues.setUriVariable(name, (String) value);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,6 @@ import org.junit.jupiter.api.Test;
|
||||||
import org.springframework.http.HttpMethod;
|
import org.springframework.http.HttpMethod;
|
||||||
import org.springframework.lang.Nullable;
|
import org.springframework.lang.Nullable;
|
||||||
import org.springframework.web.service.annotation.GetExchange;
|
import org.springframework.web.service.annotation.GetExchange;
|
||||||
import org.springframework.web.service.annotation.HttpExchange;
|
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
@ -47,7 +46,7 @@ public class HttpMethodArgumentResolverTests {
|
||||||
@Test
|
@Test
|
||||||
void shouldIgnoreArgumentsNotMatchingType() {
|
void shouldIgnoreArgumentsNotMatchingType() {
|
||||||
this.service.execute("test");
|
this.service.execute("test");
|
||||||
assertThat(getActualMethod()).isNull();
|
assertThat(getActualMethod()).isEqualTo(HttpMethod.GET);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -59,30 +58,29 @@ public class HttpMethodArgumentResolverTests {
|
||||||
@Test
|
@Test
|
||||||
void shouldIgnoreNullValue() {
|
void shouldIgnoreNullValue() {
|
||||||
this.service.executeForNull(null);
|
this.service.executeForNull(null);
|
||||||
assertThat(getActualMethod()).isNull();
|
assertThat(getActualMethod()).isEqualTo(HttpMethod.GET);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private HttpMethod getActualMethod() {
|
private HttpMethod getActualMethod() {
|
||||||
return this.clientAdapter.getRequestSpec().getHttpMethod();
|
return this.clientAdapter.getRequestValues().getHttpMethod();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private interface Service {
|
private interface Service {
|
||||||
|
|
||||||
@HttpExchange
|
@GetExchange
|
||||||
void execute(HttpMethod method);
|
void execute(HttpMethod method);
|
||||||
|
|
||||||
@GetExchange
|
@GetExchange
|
||||||
void executeGet(HttpMethod method);
|
void executeGet(HttpMethod method);
|
||||||
|
|
||||||
@HttpExchange
|
@GetExchange
|
||||||
void execute(String test);
|
void execute(String test);
|
||||||
|
|
||||||
@HttpExchange
|
@GetExchange
|
||||||
void execute(HttpMethod firstMethod, HttpMethod secondMethod);
|
void execute(HttpMethod firstMethod, HttpMethod secondMethod);
|
||||||
|
|
||||||
@HttpExchange
|
@GetExchange
|
||||||
void executeForNull(@Nullable HttpMethod method);
|
void executeForNull(@Nullable HttpMethod method);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -141,45 +141,45 @@ public class HttpServiceMethodTests {
|
||||||
@Test
|
@Test
|
||||||
void methodAnnotatedService() {
|
void methodAnnotatedService() {
|
||||||
|
|
||||||
MethodAnnotatedService service = this.clientAdapter.createService(MethodAnnotatedService.class);
|
MethodLevelAnnotatedService service = this.clientAdapter.createService(MethodLevelAnnotatedService.class);
|
||||||
|
|
||||||
service.performGet();
|
service.performGet();
|
||||||
|
|
||||||
HttpRequestSpec request = this.clientAdapter.getRequestSpec();
|
HttpRequestValues requestValues = this.clientAdapter.getRequestValues();
|
||||||
assertThat(request.getHttpMethod()).isEqualTo(HttpMethod.GET);
|
assertThat(requestValues.getHttpMethod()).isEqualTo(HttpMethod.GET);
|
||||||
assertThat(request.getUriTemplate()).isNull();
|
assertThat(requestValues.getUriTemplate()).isEqualTo("");
|
||||||
assertThat(request.getHeaders().getContentType()).isNull();
|
assertThat(requestValues.getHeaders().getContentType()).isNull();
|
||||||
assertThat(request.getHeaders().getAccept()).isEmpty();
|
assertThat(requestValues.getHeaders().getAccept()).isEmpty();
|
||||||
|
|
||||||
service.performPost();
|
service.performPost();
|
||||||
|
|
||||||
request = this.clientAdapter.getRequestSpec();
|
requestValues = this.clientAdapter.getRequestValues();
|
||||||
assertThat(request.getHttpMethod()).isEqualTo(HttpMethod.POST);
|
assertThat(requestValues.getHttpMethod()).isEqualTo(HttpMethod.POST);
|
||||||
assertThat(request.getUriTemplate()).isEqualTo("/url");
|
assertThat(requestValues.getUriTemplate()).isEqualTo("/url");
|
||||||
assertThat(request.getHeaders().getContentType()).isEqualTo(MediaType.APPLICATION_JSON);
|
assertThat(requestValues.getHeaders().getContentType()).isEqualTo(MediaType.APPLICATION_JSON);
|
||||||
assertThat(request.getHeaders().getAccept()).containsExactly(MediaType.APPLICATION_JSON);
|
assertThat(requestValues.getHeaders().getAccept()).containsExactly(MediaType.APPLICATION_JSON);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void typeAndMethodAnnotatedService() {
|
void typeAndMethodAnnotatedService() {
|
||||||
|
|
||||||
MethodAnnotatedService service = this.clientAdapter.createService(TypeAndMethodAnnotatedService.class);
|
MethodLevelAnnotatedService service = this.clientAdapter.createService(TypeAndMethodLevelAnnotatedService.class);
|
||||||
|
|
||||||
service.performGet();
|
service.performGet();
|
||||||
|
|
||||||
HttpRequestSpec request = this.clientAdapter.getRequestSpec();
|
HttpRequestValues requestValues = this.clientAdapter.getRequestValues();
|
||||||
assertThat(request.getHttpMethod()).isEqualTo(HttpMethod.GET);
|
assertThat(requestValues.getHttpMethod()).isEqualTo(HttpMethod.GET);
|
||||||
assertThat(request.getUriTemplate()).isEqualTo("/base");
|
assertThat(requestValues.getUriTemplate()).isEqualTo("/base");
|
||||||
assertThat(request.getHeaders().getContentType()).isEqualTo(MediaType.APPLICATION_CBOR);
|
assertThat(requestValues.getHeaders().getContentType()).isEqualTo(MediaType.APPLICATION_CBOR);
|
||||||
assertThat(request.getHeaders().getAccept()).containsExactly(MediaType.APPLICATION_CBOR);
|
assertThat(requestValues.getHeaders().getAccept()).containsExactly(MediaType.APPLICATION_CBOR);
|
||||||
|
|
||||||
service.performPost();
|
service.performPost();
|
||||||
|
|
||||||
request = this.clientAdapter.getRequestSpec();
|
requestValues = this.clientAdapter.getRequestValues();
|
||||||
assertThat(request.getHttpMethod()).isEqualTo(HttpMethod.POST);
|
assertThat(requestValues.getHttpMethod()).isEqualTo(HttpMethod.POST);
|
||||||
assertThat(request.getUriTemplate()).isEqualTo("/base/url");
|
assertThat(requestValues.getUriTemplate()).isEqualTo("/base/url");
|
||||||
assertThat(request.getHeaders().getContentType()).isEqualTo(MediaType.APPLICATION_JSON);
|
assertThat(requestValues.getHeaders().getContentType()).isEqualTo(MediaType.APPLICATION_JSON);
|
||||||
assertThat(request.getHeaders().getAccept()).containsExactly(MediaType.APPLICATION_JSON);
|
assertThat(requestValues.getHeaders().getAccept()).containsExactly(MediaType.APPLICATION_JSON);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void verifyClientInvocation(String methodName, @Nullable ParameterizedTypeReference<?> expectedBodyType) {
|
private void verifyClientInvocation(String methodName, @Nullable ParameterizedTypeReference<?> expectedBodyType) {
|
||||||
|
@ -191,7 +191,7 @@ public class HttpServiceMethodTests {
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
private interface ReactorService {
|
private interface ReactorService {
|
||||||
|
|
||||||
@HttpExchange
|
@GetExchange
|
||||||
Mono<Void> execute();
|
Mono<Void> execute();
|
||||||
|
|
||||||
@GetExchange
|
@GetExchange
|
||||||
|
@ -217,7 +217,7 @@ public class HttpServiceMethodTests {
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
private interface RxJavaService {
|
private interface RxJavaService {
|
||||||
|
|
||||||
@HttpExchange
|
@GetExchange
|
||||||
Completable execute();
|
Completable execute();
|
||||||
|
|
||||||
@GetExchange
|
@GetExchange
|
||||||
|
@ -243,7 +243,7 @@ public class HttpServiceMethodTests {
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
private interface BlockingService {
|
private interface BlockingService {
|
||||||
|
|
||||||
@HttpExchange
|
@GetExchange
|
||||||
void execute();
|
void execute();
|
||||||
|
|
||||||
@GetExchange
|
@GetExchange
|
||||||
|
@ -261,7 +261,7 @@ public class HttpServiceMethodTests {
|
||||||
|
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
private interface MethodAnnotatedService {
|
private interface MethodLevelAnnotatedService {
|
||||||
|
|
||||||
@GetExchange
|
@GetExchange
|
||||||
void performGet();
|
void performGet();
|
||||||
|
@ -274,7 +274,7 @@ public class HttpServiceMethodTests {
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
@HttpExchange(url = "/base", contentType = APPLICATION_CBOR_VALUE, accept = APPLICATION_CBOR_VALUE)
|
@HttpExchange(url = "/base", contentType = APPLICATION_CBOR_VALUE, accept = APPLICATION_CBOR_VALUE)
|
||||||
private interface TypeAndMethodAnnotatedService extends MethodAnnotatedService {
|
private interface TypeAndMethodLevelAnnotatedService extends MethodLevelAnnotatedService {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,7 @@ import org.junit.jupiter.api.Test;
|
||||||
import org.springframework.core.convert.support.DefaultConversionService;
|
import org.springframework.core.convert.support.DefaultConversionService;
|
||||||
import org.springframework.lang.Nullable;
|
import org.springframework.lang.Nullable;
|
||||||
import org.springframework.web.bind.annotation.PathVariable;
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
import org.springframework.web.service.annotation.HttpExchange;
|
import org.springframework.web.service.annotation.GetExchange;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
|
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
|
||||||
|
@ -143,44 +143,44 @@ class PathVariableArgumentResolverTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map<String, String> getActualUriVariables() {
|
private Map<String, String> getActualUriVariables() {
|
||||||
return this.clientAdapter.getRequestSpec().getUriVariables();
|
return this.clientAdapter.getRequestValues().getUriVariables();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
|
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
|
||||||
private interface Service {
|
private interface Service {
|
||||||
|
|
||||||
@HttpExchange
|
@GetExchange
|
||||||
void execute(@PathVariable String id);
|
void execute(@PathVariable String id);
|
||||||
|
|
||||||
@HttpExchange
|
@GetExchange
|
||||||
void executeNotRequired(@Nullable @PathVariable(required = false) String id);
|
void executeNotRequired(@Nullable @PathVariable(required = false) String id);
|
||||||
|
|
||||||
@HttpExchange
|
@GetExchange
|
||||||
void executeOptional(@PathVariable Optional<Boolean> id);
|
void executeOptional(@PathVariable Optional<Boolean> id);
|
||||||
|
|
||||||
@HttpExchange
|
@GetExchange
|
||||||
void executeOptionalNotRequired(@PathVariable(required = false) Optional<String> id);
|
void executeOptionalNotRequired(@PathVariable(required = false) Optional<String> id);
|
||||||
|
|
||||||
@HttpExchange
|
@GetExchange
|
||||||
void executeNamedWithValue(@Nullable @PathVariable(name = "test", value = "id") String employeeId);
|
void executeNamedWithValue(@Nullable @PathVariable(name = "test", value = "id") String employeeId);
|
||||||
|
|
||||||
@HttpExchange
|
@GetExchange
|
||||||
void executeNamed(@PathVariable(name = "id") String employeeId);
|
void executeNamed(@PathVariable(name = "id") String employeeId);
|
||||||
|
|
||||||
@HttpExchange
|
@GetExchange
|
||||||
void executeValueNamed(@PathVariable("id") String employeeId);
|
void executeValueNamed(@PathVariable("id") String employeeId);
|
||||||
|
|
||||||
@HttpExchange
|
@GetExchange
|
||||||
void execute(@PathVariable Object id);
|
void execute(@PathVariable Object id);
|
||||||
|
|
||||||
@HttpExchange
|
@GetExchange
|
||||||
void execute(@PathVariable Boolean id);
|
void execute(@PathVariable Boolean id);
|
||||||
|
|
||||||
@HttpExchange
|
@GetExchange
|
||||||
void executeValueMap(@Nullable @PathVariable Map<String, String> map);
|
void executeValueMap(@Nullable @PathVariable Map<String, String> map);
|
||||||
|
|
||||||
@HttpExchange
|
@GetExchange
|
||||||
void executeOptionalValueMap(@PathVariable Map<String, Optional<String>> map);
|
void executeOptionalValueMap(@PathVariable Map<String, Optional<String>> map);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -44,7 +44,7 @@ class TestHttpClientAdapter implements HttpClientAdapter {
|
||||||
private String invokedMethodName;
|
private String invokedMethodName;
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private HttpRequestSpec requestSpec;
|
private HttpRequestValues requestValues;
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private ParameterizedTypeReference<?> bodyType;
|
private ParameterizedTypeReference<?> bodyType;
|
||||||
|
@ -67,9 +67,9 @@ class TestHttpClientAdapter implements HttpClientAdapter {
|
||||||
return this.invokedMethodName;
|
return this.invokedMethodName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public HttpRequestSpec getRequestSpec() {
|
public HttpRequestValues getRequestValues() {
|
||||||
assertThat(this.requestSpec).isNotNull();
|
assertThat(this.requestValues).isNotNull();
|
||||||
return this.requestSpec;
|
return this.requestValues;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
|
@ -81,56 +81,56 @@ class TestHttpClientAdapter implements HttpClientAdapter {
|
||||||
// HttpClientAdapter implementation
|
// HttpClientAdapter implementation
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Mono<Void> requestToVoid(HttpRequestSpec requestSpec) {
|
public Mono<Void> requestToVoid(HttpRequestValues requestValues) {
|
||||||
saveInput("requestToVoid", requestSpec, null);
|
saveInput("requestToVoid", requestValues, null);
|
||||||
return Mono.empty();
|
return Mono.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Mono<HttpHeaders> requestToHeaders(HttpRequestSpec requestSpec) {
|
public Mono<HttpHeaders> requestToHeaders(HttpRequestValues requestValues) {
|
||||||
saveInput("requestToHeaders", requestSpec, null);
|
saveInput("requestToHeaders", requestValues, null);
|
||||||
return Mono.just(new HttpHeaders());
|
return Mono.just(new HttpHeaders());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <T> Mono<T> requestToBody(HttpRequestSpec requestSpec, ParameterizedTypeReference<T> bodyType) {
|
public <T> Mono<T> requestToBody(HttpRequestValues requestValues, ParameterizedTypeReference<T> bodyType) {
|
||||||
saveInput("requestToBody", requestSpec, bodyType);
|
saveInput("requestToBody", requestValues, bodyType);
|
||||||
return (Mono<T>) Mono.just(getInvokedMethodName());
|
return (Mono<T>) Mono.just(getInvokedMethodName());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <T> Flux<T> requestToBodyFlux(HttpRequestSpec requestSpec, ParameterizedTypeReference<T> bodyType) {
|
public <T> Flux<T> requestToBodyFlux(HttpRequestValues requestValues, ParameterizedTypeReference<T> bodyType) {
|
||||||
saveInput("requestToBodyFlux", requestSpec, bodyType);
|
saveInput("requestToBodyFlux", requestValues, bodyType);
|
||||||
return (Flux<T>) Flux.just("request", "To", "Body", "Flux");
|
return (Flux<T>) Flux.just("request", "To", "Body", "Flux");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Mono<ResponseEntity<Void>> requestToBodilessEntity(HttpRequestSpec requestSpec) {
|
public Mono<ResponseEntity<Void>> requestToBodilessEntity(HttpRequestValues requestValues) {
|
||||||
saveInput("requestToBodilessEntity", requestSpec, null);
|
saveInput("requestToBodilessEntity", requestValues, null);
|
||||||
return Mono.just(ResponseEntity.ok().build());
|
return Mono.just(ResponseEntity.ok().build());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <T> Mono<ResponseEntity<T>> requestToEntity(
|
public <T> Mono<ResponseEntity<T>> requestToEntity(
|
||||||
HttpRequestSpec requestSpec, ParameterizedTypeReference<T> type) {
|
HttpRequestValues requestValues, ParameterizedTypeReference<T> type) {
|
||||||
|
|
||||||
saveInput("requestToEntity", requestSpec, type);
|
saveInput("requestToEntity", requestValues, type);
|
||||||
return Mono.just((ResponseEntity<T>) ResponseEntity.ok("requestToEntity"));
|
return Mono.just((ResponseEntity<T>) ResponseEntity.ok("requestToEntity"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <T> Mono<ResponseEntity<Flux<T>>> requestToEntityFlux(
|
public <T> Mono<ResponseEntity<Flux<T>>> requestToEntityFlux(
|
||||||
HttpRequestSpec requestSpec, ParameterizedTypeReference<T> bodyType) {
|
HttpRequestValues requestValues, ParameterizedTypeReference<T> bodyType) {
|
||||||
|
|
||||||
saveInput("requestToEntityFlux", requestSpec, bodyType);
|
saveInput("requestToEntityFlux", requestValues, bodyType);
|
||||||
return Mono.just(ResponseEntity.ok((Flux<T>) Flux.just("request", "To", "Entity", "Flux")));
|
return Mono.just(ResponseEntity.ok((Flux<T>) Flux.just("request", "To", "Entity", "Flux")));
|
||||||
}
|
}
|
||||||
|
|
||||||
private <T> void saveInput(
|
private <T> void saveInput(
|
||||||
String methodName, HttpRequestSpec requestSpec, @Nullable ParameterizedTypeReference<T> bodyType) {
|
String methodName, HttpRequestValues requestValues, @Nullable ParameterizedTypeReference<T> bodyType) {
|
||||||
|
|
||||||
this.invokedMethodName = methodName;
|
this.invokedMethodName = methodName;
|
||||||
this.requestSpec = requestSpec;
|
this.requestValues = requestValues;
|
||||||
this.bodyType = bodyType;
|
this.bodyType = bodyType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,10 +24,11 @@ import org.springframework.core.ParameterizedTypeReference;
|
||||||
import org.springframework.http.HttpHeaders;
|
import org.springframework.http.HttpHeaders;
|
||||||
import org.springframework.http.HttpMethod;
|
import org.springframework.http.HttpMethod;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
import org.springframework.web.reactive.function.client.ClientResponse;
|
import org.springframework.web.reactive.function.client.ClientResponse;
|
||||||
import org.springframework.web.reactive.function.client.WebClient;
|
import org.springframework.web.reactive.function.client.WebClient;
|
||||||
import org.springframework.web.service.invoker.HttpClientAdapter;
|
import org.springframework.web.service.invoker.HttpClientAdapter;
|
||||||
import org.springframework.web.service.invoker.HttpRequestSpec;
|
import org.springframework.web.service.invoker.HttpRequestValues;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -47,67 +48,68 @@ public class WebClientAdapter implements HttpClientAdapter {
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Mono<Void> requestToVoid(HttpRequestSpec requestSpec) {
|
public Mono<Void> requestToVoid(HttpRequestValues requestValues) {
|
||||||
return toBodySpec(requestSpec).exchangeToMono(ClientResponse::releaseBody);
|
return toBodySpec(requestValues).exchangeToMono(ClientResponse::releaseBody);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Mono<HttpHeaders> requestToHeaders(HttpRequestSpec requestSpec) {
|
public Mono<HttpHeaders> requestToHeaders(HttpRequestValues requestValues) {
|
||||||
return toBodySpec(requestSpec).retrieve().toBodilessEntity().map(ResponseEntity::getHeaders);
|
return toBodySpec(requestValues).retrieve().toBodilessEntity().map(ResponseEntity::getHeaders);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <T> Mono<T> requestToBody(HttpRequestSpec reqrequestSpecest, ParameterizedTypeReference<T> bodyType) {
|
public <T> Mono<T> requestToBody(HttpRequestValues requestValues, ParameterizedTypeReference<T> bodyType) {
|
||||||
return toBodySpec(reqrequestSpecest).retrieve().bodyToMono(bodyType);
|
return toBodySpec(requestValues).retrieve().bodyToMono(bodyType);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <T> Flux<T> requestToBodyFlux(HttpRequestSpec requestSpec, ParameterizedTypeReference<T> bodyType) {
|
public <T> Flux<T> requestToBodyFlux(HttpRequestValues requestValues, ParameterizedTypeReference<T> bodyType) {
|
||||||
return toBodySpec(requestSpec).retrieve().bodyToFlux(bodyType);
|
return toBodySpec(requestValues).retrieve().bodyToFlux(bodyType);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Mono<ResponseEntity<Void>> requestToBodilessEntity(HttpRequestSpec requestSpec) {
|
public Mono<ResponseEntity<Void>> requestToBodilessEntity(HttpRequestValues requestValues) {
|
||||||
return toBodySpec(requestSpec).retrieve().toBodilessEntity();
|
return toBodySpec(requestValues).retrieve().toBodilessEntity();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <T> Mono<ResponseEntity<T>> requestToEntity(HttpRequestSpec spec, ParameterizedTypeReference<T> bodyType) {
|
public <T> Mono<ResponseEntity<T>> requestToEntity(HttpRequestValues requestValues, ParameterizedTypeReference<T> bodyType) {
|
||||||
return toBodySpec(spec).retrieve().toEntity(bodyType);
|
return toBodySpec(requestValues).retrieve().toEntity(bodyType);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <T> Mono<ResponseEntity<Flux<T>>> requestToEntityFlux(HttpRequestSpec spec, ParameterizedTypeReference<T> bodyType) {
|
public <T> Mono<ResponseEntity<Flux<T>>> requestToEntityFlux(HttpRequestValues requestValues, ParameterizedTypeReference<T> bodyType) {
|
||||||
return toBodySpec(spec).retrieve().toEntityFlux(bodyType);
|
return toBodySpec(requestValues).retrieve().toEntityFlux(bodyType);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("ReactiveStreamsUnusedPublisher")
|
@SuppressWarnings("ReactiveStreamsUnusedPublisher")
|
||||||
private WebClient.RequestBodySpec toBodySpec(HttpRequestSpec requestSpec) {
|
private WebClient.RequestBodySpec toBodySpec(HttpRequestValues requestValues) {
|
||||||
|
|
||||||
|
HttpMethod httpMethod = requestValues.getHttpMethod();
|
||||||
|
Assert.notNull(httpMethod, "No HttpMethod");
|
||||||
|
|
||||||
HttpMethod httpMethod = requestSpec.getHttpMethodRequired();
|
|
||||||
WebClient.RequestBodyUriSpec uriSpec = this.webClient.method(httpMethod);
|
WebClient.RequestBodyUriSpec uriSpec = this.webClient.method(httpMethod);
|
||||||
|
|
||||||
WebClient.RequestBodySpec bodySpec;
|
WebClient.RequestBodySpec bodySpec;
|
||||||
if (requestSpec.getUri() != null) {
|
if (requestValues.getUri() != null) {
|
||||||
bodySpec = uriSpec.uri(requestSpec.getUri());
|
bodySpec = uriSpec.uri(requestValues.getUri());
|
||||||
}
|
}
|
||||||
else if (requestSpec.getUriTemplate() != null) {
|
else if (requestValues.getUriTemplate() != null) {
|
||||||
bodySpec = (!requestSpec.getUriVariables().isEmpty() ?
|
bodySpec = uriSpec.uri(requestValues.getUriTemplate(), requestValues.getUriVariables());
|
||||||
uriSpec.uri(requestSpec.getUriTemplate(), requestSpec.getUriVariables()) :
|
|
||||||
uriSpec.uri(requestSpec.getUriTemplate(), requestSpec.getUriVariableValues()));
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
bodySpec = uriSpec.uri("");
|
throw new IllegalStateException("Neither full URL nor URI template");
|
||||||
}
|
}
|
||||||
|
|
||||||
bodySpec.headers(headers -> headers.putAll(requestSpec.getHeaders()));
|
bodySpec.headers(headers -> headers.putAll(requestValues.getHeaders()));
|
||||||
bodySpec.cookies(cookies -> cookies.putAll(requestSpec.getCookies()));
|
bodySpec.cookies(cookies -> cookies.putAll(requestValues.getCookies()));
|
||||||
|
|
||||||
if (requestSpec.getBodyValue() != null) {
|
if (requestValues.getBodyValue() != null) {
|
||||||
bodySpec.bodyValue(requestSpec.getBodyValue());
|
bodySpec.bodyValue(requestValues.getBodyValue());
|
||||||
}
|
}
|
||||||
else if (requestSpec.getBodyPublisher() != null) {
|
else if (requestValues.getBody() != null) {
|
||||||
bodySpec.body(requestSpec.getBodyPublisher(), requestSpec.getBodyPublisherElementType());
|
Assert.notNull(requestValues.getBodyElementType(), "Publisher body element type is required");
|
||||||
|
bodySpec.body(requestValues.getBody(), requestValues.getBodyElementType());
|
||||||
}
|
}
|
||||||
|
|
||||||
return bodySpec;
|
return bodySpec;
|
||||||
|
|
Loading…
Reference in New Issue