Browse Source
Separate collection and handling of reactive request values into a subclass of HttpRequestValues. Closes gh-30117pull/30869/head
9 changed files with 435 additions and 103 deletions
@ -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); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
Loading…
Reference in new issue