Polish
This commit is contained in:
parent
4fef1fe820
commit
313c6cef32
|
|
@ -48,6 +48,7 @@ import org.springframework.util.MultiValueMap;
|
|||
* </pre>
|
||||
|
||||
* @author Arjen Poutsma
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 5.0.2
|
||||
* @see <a href="https://tools.ietf.org/html/rfc7578">RFC 7578</a>
|
||||
*/
|
||||
|
|
@ -64,38 +65,22 @@ public final class MultipartBodyBuilder {
|
|||
|
||||
|
||||
/**
|
||||
* Builds the multipart body.
|
||||
* @return the built body
|
||||
*/
|
||||
public MultiValueMap<String, HttpEntity<?>> build() {
|
||||
MultiValueMap<String, HttpEntity<?>> result = new LinkedMultiValueMap<>(this.parts.size());
|
||||
for (Map.Entry<String, List<DefaultPartBuilder>> entry : this.parts.entrySet()) {
|
||||
for (DefaultPartBuilder builder : entry.getValue()) {
|
||||
HttpEntity<?> entity = builder.build();
|
||||
result.add(entry.getKey(), entity);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a part to this builder, allowing for further header customization with the returned
|
||||
* {@link PartBuilder}.
|
||||
* @param name the name of the part to add (may not be empty)
|
||||
* @param part the part to add
|
||||
* @return a builder that allows for further header customization
|
||||
* Add a part from an Object.
|
||||
* @param name the name of the part to add
|
||||
* @param part the part data
|
||||
* @return builder that allows for further customization of part headers
|
||||
*/
|
||||
public PartBuilder part(String name, Object part) {
|
||||
return part(name, part, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a part to this builder, allowing for further header customization with the returned
|
||||
* {@link PartBuilder}.
|
||||
* @param name the name of the part to add (may not be empty)
|
||||
* @param part the part to add
|
||||
* @param contentType the {@code Content-Type} header for the part (may be {@code null})
|
||||
* @return a builder that allows for further header customization
|
||||
* Variant of {@link #part(String, Object)} that also accepts a MediaType
|
||||
* which is used to determine how to encode the part.
|
||||
* @param name the name of the part to add
|
||||
* @param part the part data
|
||||
* @param contentType the media type for the part
|
||||
* @return builder that allows for further customization of part headers
|
||||
*/
|
||||
public PartBuilder part(String name, Object part, @Nullable MediaType contentType) {
|
||||
Assert.hasLength(name, "'name' must not be empty");
|
||||
|
|
@ -121,18 +106,18 @@ public final class MultipartBodyBuilder {
|
|||
if (contentType != null) {
|
||||
partHeaders.setContentType(contentType);
|
||||
}
|
||||
DefaultPartBuilder builder = new DefaultPartBuilder(partBody, partHeaders);
|
||||
|
||||
DefaultPartBuilder builder = new DefaultPartBuilder(partHeaders, partBody);
|
||||
this.parts.add(name, builder);
|
||||
return builder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a {@link Publisher} part to this builder, allowing for further header customization with
|
||||
* the returned {@link PartBuilder}.
|
||||
* @param name the name of the part to add (may not be empty)
|
||||
* @param publisher the contents of the part to add
|
||||
* @param elementClass the class of elements contained in the publisher
|
||||
* @return a builder that allows for further header customization
|
||||
* Add an asynchronous part with {@link Publisher}-based content.
|
||||
* @param name the name of the part to add
|
||||
* @param publisher the part contents
|
||||
* @param elementClass the type of elements contained in the publisher
|
||||
* @return builder that allows for further customization of part headers
|
||||
*/
|
||||
public <T, P extends Publisher<T>> PartBuilder asyncPart(String name, P publisher,
|
||||
Class<T> elementClass) {
|
||||
|
|
@ -143,21 +128,21 @@ public final class MultipartBodyBuilder {
|
|||
Assert.notNull(publisher, "'publisher' must not be null");
|
||||
Assert.notNull(elementType, "'elementType' must not be null");
|
||||
|
||||
HttpHeaders partHeaders = new HttpHeaders();
|
||||
PublisherPartBuilder<T, P> builder =
|
||||
new PublisherPartBuilder<>(publisher, elementClass, partHeaders);
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
PublisherPartBuilder<T, P> builder = new PublisherPartBuilder<>(headers, publisher, elementClass);
|
||||
this.parts.add(name, builder);
|
||||
return builder;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a {@link Publisher} part to this builder, allowing for further header customization with
|
||||
* the returned {@link PartBuilder}.
|
||||
* @param name the name of the part to add (may not be empty)
|
||||
* @param publisher the contents of the part to add
|
||||
* Variant of {@link #asyncPart(String, Publisher, Class)} that accepts a
|
||||
* {@link ParameterizedTypeReference} for the element type, which allows
|
||||
* specifying generic type information.
|
||||
* @param name the name of the part to add
|
||||
* @param publisher the part contents
|
||||
* @param typeReference the type of elements contained in the publisher
|
||||
* @return a builder that allows for further header customization
|
||||
* @return builder that allows for further customization of part headers
|
||||
*/
|
||||
public <T, P extends Publisher<T>> PartBuilder asyncPart(String name, P publisher,
|
||||
ParameterizedTypeReference<T> typeReference) {
|
||||
|
|
@ -168,30 +153,44 @@ public final class MultipartBodyBuilder {
|
|||
Assert.notNull(publisher, "'publisher' must not be null");
|
||||
Assert.notNull(elementType1, "'typeReference' must not be null");
|
||||
|
||||
HttpHeaders partHeaders = new HttpHeaders();
|
||||
PublisherPartBuilder<T, P> builder =
|
||||
new PublisherPartBuilder<>(publisher, typeReference, partHeaders);
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
PublisherPartBuilder<T, P> builder = new PublisherPartBuilder<>(publisher, typeReference, headers);
|
||||
this.parts.add(name, builder);
|
||||
return builder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builder interface that allows for customization of part headers.
|
||||
* Return a {@code MultiValueMap} with the configured parts.
|
||||
*/
|
||||
public MultiValueMap<String, HttpEntity<?>> build() {
|
||||
MultiValueMap<String, HttpEntity<?>> result = new LinkedMultiValueMap<>(this.parts.size());
|
||||
for (Map.Entry<String, List<DefaultPartBuilder>> entry : this.parts.entrySet()) {
|
||||
for (DefaultPartBuilder builder : entry.getValue()) {
|
||||
HttpEntity<?> entity = builder.build();
|
||||
result.add(entry.getKey(), entity);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Builder that allows for further customization of part headers.
|
||||
*/
|
||||
public interface PartBuilder {
|
||||
|
||||
/**
|
||||
* Add the given part-specific header values under the given name.
|
||||
* Add part header values.
|
||||
* @param headerName the part header name
|
||||
* @param headerValues the part header value(s)
|
||||
* @return this builder
|
||||
* @see HttpHeaders#add(String, String)
|
||||
* @see HttpHeaders#addAll(String, List)
|
||||
*/
|
||||
PartBuilder header(String headerName, String... headerValues);
|
||||
|
||||
/**
|
||||
* Manipulate the part's headers with the given consumer.
|
||||
* @param headersConsumer a function that consumes the {@code HttpHeaders}
|
||||
* Manipulate the part headers through the given consumer.
|
||||
* @param headersConsumer consumer to manipulate the part headers with
|
||||
* @return this builder
|
||||
*/
|
||||
PartBuilder headers(Consumer<HttpHeaders> headersConsumer);
|
||||
|
|
@ -200,14 +199,15 @@ public final class MultipartBodyBuilder {
|
|||
|
||||
private static class DefaultPartBuilder implements PartBuilder {
|
||||
|
||||
protected final HttpHeaders headers;
|
||||
|
||||
@Nullable
|
||||
protected final Object body;
|
||||
|
||||
protected final HttpHeaders headers;
|
||||
|
||||
public DefaultPartBuilder(@Nullable Object body, HttpHeaders headers) {
|
||||
this.body = body;
|
||||
public DefaultPartBuilder(HttpHeaders headers, @Nullable Object body) {
|
||||
this.headers = headers;
|
||||
this.body = body;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -228,20 +228,19 @@ public final class MultipartBodyBuilder {
|
|||
}
|
||||
}
|
||||
|
||||
private static class PublisherPartBuilder<S, P extends Publisher<S>>
|
||||
extends DefaultPartBuilder {
|
||||
|
||||
private static class PublisherPartBuilder<S, P extends Publisher<S>> extends DefaultPartBuilder {
|
||||
|
||||
private final ResolvableType resolvableType;
|
||||
|
||||
public PublisherPartBuilder(P body, Class<S> elementClass, HttpHeaders headers) {
|
||||
super(body, headers);
|
||||
|
||||
public PublisherPartBuilder(HttpHeaders headers, P body, Class<S> elementClass) {
|
||||
super(headers, body);
|
||||
this.resolvableType = ResolvableType.forClass(elementClass);
|
||||
}
|
||||
|
||||
public PublisherPartBuilder(P body, ParameterizedTypeReference<S> typeReference,
|
||||
HttpHeaders headers) {
|
||||
|
||||
super(body, headers);
|
||||
public PublisherPartBuilder(P body, ParameterizedTypeReference<S> typeReference, HttpHeaders headers) {
|
||||
super(headers, body);
|
||||
this.resolvableType = ResolvableType.forType(typeReference);
|
||||
}
|
||||
|
||||
|
|
@ -250,14 +249,15 @@ public final class MultipartBodyBuilder {
|
|||
public HttpEntity<?> build() {
|
||||
P publisher = (P) this.body;
|
||||
Assert.state(publisher != null, "'publisher' must not be null");
|
||||
return new PublisherEntity<>(publisher, this.resolvableType, this.headers);
|
||||
return new PublisherEntity<>(this.headers, publisher, this.resolvableType);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Specific subtype of {@link HttpEntity} for containing {@link Publisher}s as body.
|
||||
* Exposes the type contained in the publisher through {@link #getResolvableType()}.
|
||||
* Specialization of {@link HttpEntity} for use with a
|
||||
* {@link Publisher}-based body, for which we also need to keep track of
|
||||
* the element type.
|
||||
* @param <T> The type contained in the publisher
|
||||
* @param <P> The publisher
|
||||
*/
|
||||
|
|
@ -266,8 +266,9 @@ public final class MultipartBodyBuilder {
|
|||
private final ResolvableType resolvableType;
|
||||
|
||||
|
||||
PublisherEntity(P publisher, ResolvableType resolvableType,
|
||||
@Nullable MultiValueMap<String, String> headers) {
|
||||
private PublisherEntity(@Nullable MultiValueMap<String, String> headers, P publisher,
|
||||
ResolvableType resolvableType) {
|
||||
|
||||
super(publisher, headers);
|
||||
Assert.notNull(publisher, "'publisher' must not be null");
|
||||
Assert.notNull(resolvableType, "'resolvableType' must not be null");
|
||||
|
|
@ -275,7 +276,7 @@ public final class MultipartBodyBuilder {
|
|||
}
|
||||
|
||||
/**
|
||||
* Return the resolvable type for this entry.
|
||||
* Return the element type for the {@code Publisher} body.
|
||||
*/
|
||||
public ResolvableType getResolvableType() {
|
||||
return this.resolvableType;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
* Copyright 2002-2018 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.
|
||||
|
|
@ -37,48 +37,58 @@ import static org.junit.Assert.*;
|
|||
public class MultipartBodyBuilderTests {
|
||||
|
||||
@Test
|
||||
public void builder() throws Exception {
|
||||
public void builder() {
|
||||
|
||||
MultipartBodyBuilder builder = new MultipartBodyBuilder();
|
||||
|
||||
MultiValueMap<String, String> multipartData = new LinkedMultiValueMap<>();
|
||||
multipartData.add("form field", "form value");
|
||||
builder.part("key", multipartData).header("foo", "bar");
|
||||
|
||||
Resource logo = new ClassPathResource("/org/springframework/http/converter/logo.jpg");
|
||||
builder.part("logo", logo).header("baz", "qux");
|
||||
|
||||
HttpHeaders entityHeaders = new HttpHeaders();
|
||||
entityHeaders.add("foo", "bar");
|
||||
HttpEntity<String> entity = new HttpEntity<>("body", entityHeaders);
|
||||
Publisher<String> publisher = Flux.just("foo", "bar", "baz");
|
||||
|
||||
MultipartBodyBuilder builder = new MultipartBodyBuilder();
|
||||
builder.part("key", multipartData).header("foo", "bar");
|
||||
builder.part("logo", logo).header("baz", "qux");
|
||||
builder.part("entity", entity).header("baz", "qux");
|
||||
|
||||
Publisher<String> publisher = Flux.just("foo", "bar", "baz");
|
||||
builder.asyncPart("publisherClass", publisher, String.class).header("baz", "qux");
|
||||
builder.asyncPart("publisherPtr", publisher, new ParameterizedTypeReference<String>() {}).header("baz", "qux");
|
||||
|
||||
MultiValueMap<String, HttpEntity<?>> result = builder.build();
|
||||
|
||||
assertEquals(5, result.size());
|
||||
assertNotNull(result.getFirst("key"));
|
||||
assertEquals(multipartData, result.getFirst("key").getBody());
|
||||
assertEquals("bar", result.getFirst("key").getHeaders().getFirst("foo"));
|
||||
HttpEntity<?> resultEntity = result.getFirst("key");
|
||||
assertNotNull(resultEntity);
|
||||
assertEquals(multipartData, resultEntity.getBody());
|
||||
assertEquals("bar", resultEntity.getHeaders().getFirst("foo"));
|
||||
|
||||
assertNotNull(result.getFirst("logo"));
|
||||
assertEquals(logo, result.getFirst("logo").getBody());
|
||||
assertEquals("qux", result.getFirst("logo").getHeaders().getFirst("baz"));
|
||||
resultEntity = result.getFirst("logo");
|
||||
assertNotNull(resultEntity);
|
||||
assertEquals(logo, resultEntity.getBody());
|
||||
assertEquals("qux", resultEntity.getHeaders().getFirst("baz"));
|
||||
|
||||
assertNotNull(result.getFirst("entity"));
|
||||
assertEquals("body", result.getFirst("entity").getBody());
|
||||
assertEquals("bar", result.getFirst("entity").getHeaders().getFirst("foo"));
|
||||
assertEquals("qux", result.getFirst("entity").getHeaders().getFirst("baz"));
|
||||
resultEntity = result.getFirst("entity");
|
||||
assertNotNull(resultEntity);
|
||||
assertEquals("body", resultEntity.getBody());
|
||||
assertEquals("bar", resultEntity.getHeaders().getFirst("foo"));
|
||||
assertEquals("qux", resultEntity.getHeaders().getFirst("baz"));
|
||||
|
||||
assertNotNull(result.getFirst("publisherClass"));
|
||||
assertEquals(publisher, result.getFirst("publisherClass").getBody());
|
||||
assertEquals(ResolvableType.forClass(String.class), ((MultipartBodyBuilder.PublisherEntity<?,?>) result.getFirst("publisherClass")).getResolvableType());
|
||||
assertEquals("qux", result.getFirst("publisherClass").getHeaders().getFirst("baz"));
|
||||
resultEntity = result.getFirst("publisherClass");
|
||||
assertNotNull(resultEntity);
|
||||
assertEquals(publisher, resultEntity.getBody());
|
||||
assertEquals(ResolvableType.forClass(String.class),
|
||||
((MultipartBodyBuilder.PublisherEntity<?,?>) resultEntity).getResolvableType());
|
||||
assertEquals("qux", resultEntity.getHeaders().getFirst("baz"));
|
||||
|
||||
assertNotNull(result.getFirst("publisherPtr"));
|
||||
assertEquals(publisher, result.getFirst("publisherPtr").getBody());
|
||||
assertEquals(ResolvableType.forClass(String.class), ((MultipartBodyBuilder.PublisherEntity<?,?>) result.getFirst("publisherPtr")).getResolvableType());
|
||||
assertEquals("qux", result.getFirst("publisherPtr").getHeaders().getFirst("baz"));
|
||||
resultEntity = result.getFirst("publisherPtr");
|
||||
assertNotNull(resultEntity);
|
||||
assertEquals(publisher, resultEntity.getBody());
|
||||
assertEquals(ResolvableType.forClass(String.class),
|
||||
((MultipartBodyBuilder.PublisherEntity<?,?>) resultEntity).getResolvableType());
|
||||
assertEquals("qux", resultEntity.getHeaders().getFirst("baz"));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -200,17 +200,15 @@ public abstract class BodyInserters {
|
|||
*
|
||||
* <p>Note that you can also use the {@code syncBody(Object)} method in the
|
||||
* request builders of both the {@code WebClient} and {@code WebTestClient}.
|
||||
* In that case the setting of the content type is also not required, just
|
||||
* be sure the map contains String values only or otherwise it would be
|
||||
* In that case the setting of the request content type is also not required,
|
||||
* just be sure the map contains String values only or otherwise it would be
|
||||
* interpreted as a multipart request.
|
||||
*
|
||||
* @param formData the form data to write to the output message
|
||||
* @return a {@code FormInserter} that writes form data
|
||||
* @return the inserter that allows adding more form data
|
||||
*/
|
||||
public static FormInserter<String> fromFormData(MultiValueMap<String, String> formData) {
|
||||
|
||||
Assert.notNull(formData, "'formData' must not be null");
|
||||
|
||||
return new DefaultFormInserter().with(formData);
|
||||
}
|
||||
|
||||
|
|
@ -218,36 +216,27 @@ public abstract class BodyInserters {
|
|||
* Return a {@link FormInserter} that writes the given key-value pair as
|
||||
* URL-encoded form data. The returned inserter allows for additional
|
||||
* entries to be added via {@link FormInserter#with(String, Object)}.
|
||||
* @param key the key to add to the form
|
||||
* @param name the key to add to the form
|
||||
* @param value the value to add to the form
|
||||
* @return a {@code FormInserter} that writes form data
|
||||
* @return the inserter that allows adding more form data
|
||||
*/
|
||||
public static FormInserter<String> fromFormData(String key, String value) {
|
||||
Assert.notNull(key, "'key' must not be null");
|
||||
public static FormInserter<String> fromFormData(String name, String value) {
|
||||
Assert.notNull(name, "'key' must not be null");
|
||||
Assert.notNull(value, "'value' must not be null");
|
||||
|
||||
return new DefaultFormInserter().with(key, value);
|
||||
return new DefaultFormInserter().with(name, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a {@code FormInserter} that writes the given {@code MultiValueMap}
|
||||
* as multipart data. The values in the {@code MultiValueMap} can be any
|
||||
* Object representing the body of the part, or an
|
||||
* {@link org.springframework.http.HttpEntity HttpEntity} representing a part
|
||||
* with body and headers. The {@code MultiValueMap} can be built conveniently
|
||||
* using {@link org.springframework.http.client.MultipartBodyBuilder
|
||||
* MultipartBodyBuilder}. Also the returned inserter allows for additional
|
||||
* entries to be added via {@link FormInserter#with(String, Object)}.
|
||||
* Return a {@link MultipartInserter} that writes the given
|
||||
* {@code MultiValueMap} as multipart data. Values in the map can be an
|
||||
* Object or an {@link HttpEntity}.
|
||||
*
|
||||
* <p>Note that you can also use the {@code syncBody(Object)} method in the
|
||||
* request builders of both the {@code WebClient} and {@code WebTestClient}.
|
||||
* In that case the setting of the content type is also not required, just
|
||||
* be sure the map contains at least one non-String value or otherwise,
|
||||
* without a content-type header as a hint, it would be interpreted as a
|
||||
* plain form data request.
|
||||
* <p>Note that you can also build the multipart data externally with
|
||||
* {@link MultipartBodyBuilder}, and pass the resulting map directly to the
|
||||
* {@code syncBody(Object)} shortcut method in {@code WebClient}.
|
||||
*
|
||||
* @param multipartData the form data to write to the output message
|
||||
* @return a {@code BodyInserter} that writes multipart data
|
||||
* @return the inserter that allows adding more parts
|
||||
* @see MultipartBodyBuilder
|
||||
*/
|
||||
public static MultipartInserter fromMultipartData(MultiValueMap<String, ?> multipartData) {
|
||||
|
|
@ -256,57 +245,69 @@ public abstract class BodyInserters {
|
|||
}
|
||||
|
||||
/**
|
||||
* A variant of {@link #fromMultipartData(MultiValueMap)} for adding
|
||||
* parts as name-value pairs in-line vs building a {@code MultiValueMap}
|
||||
* and passing it in.
|
||||
* @param key the part name
|
||||
* Return a {@link MultipartInserter} that writes the given parts,
|
||||
* as multipart data. Values in the map can be an Object or an
|
||||
* {@link HttpEntity}.
|
||||
*
|
||||
* <p>Note that you can also build the multipart data externally with
|
||||
* {@link MultipartBodyBuilder}, and pass the resulting map directly to the
|
||||
* {@code syncBody(Object)} shortcut method in {@code WebClient}.
|
||||
*
|
||||
* @param name the part name
|
||||
* @param value the part value, an Object or {@code HttpEntity}
|
||||
* @return a {@code FormInserter} that can writes the provided multipart
|
||||
* data and also allows adding more parts
|
||||
* @return the inserter that allows adding more parts
|
||||
*/
|
||||
public static MultipartInserter fromMultipartData(String key, Object value) {
|
||||
Assert.notNull(key, "'key' must not be null");
|
||||
public static MultipartInserter fromMultipartData(String name, Object value) {
|
||||
Assert.notNull(name, "'key' must not be null");
|
||||
Assert.notNull(value, "'value' must not be null");
|
||||
|
||||
return new DefaultMultipartInserter().with(key, value);
|
||||
return new DefaultMultipartInserter().with(name, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* A variant of {@link #fromMultipartData(MultiValueMap)} for adding asynchronous data as a
|
||||
* part in-line vs building a {@code MultiValueMap} and passing it in.
|
||||
* @param key the part name
|
||||
* Return a {@link MultipartInserter} that writes the given asynchronous parts,
|
||||
* as multipart data.
|
||||
*
|
||||
* <p>Note that you can also build the multipart data externally with
|
||||
* {@link MultipartBodyBuilder}, and pass the resulting map directly to the
|
||||
* {@code syncBody(Object)} shortcut method in {@code WebClient}.
|
||||
*
|
||||
* @param name the part name
|
||||
* @param publisher the publisher that forms the part value
|
||||
* @param elementClass the class contained in the {@code publisher}
|
||||
* @return a {@code FormInserter} that can writes the provided multipart
|
||||
* data and also allows adding more parts
|
||||
* @return the inserter that allows adding more parts
|
||||
*/
|
||||
public static <T, P extends Publisher<T>> MultipartInserter fromMultipartAsyncData(String key,
|
||||
public static <T, P extends Publisher<T>> MultipartInserter fromMultipartAsyncData(String name,
|
||||
P publisher, Class<T> elementClass) {
|
||||
|
||||
Assert.notNull(key, "'key' must not be null");
|
||||
Assert.notNull(name, "'key' must not be null");
|
||||
Assert.notNull(publisher, "'publisher' must not be null");
|
||||
Assert.notNull(elementClass, "'elementClass' must not be null");
|
||||
|
||||
return new DefaultMultipartInserter().withPublisher(key, publisher, elementClass);
|
||||
return new DefaultMultipartInserter().withPublisher(name, publisher, elementClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* A variant of {@link #fromMultipartData(MultiValueMap)} for adding asynchronous data as a
|
||||
* part in-line vs building a {@code MultiValueMap} and passing it in.
|
||||
* @param key the part name
|
||||
* Variant of {@link #fromMultipartAsyncData(String, Publisher, Class)} that
|
||||
* accepts a {@link ParameterizedTypeReference} for the element type, which
|
||||
* allows specifying generic type information.
|
||||
*
|
||||
* <p>Note that you can also build the multipart data externally with
|
||||
* {@link MultipartBodyBuilder}, and pass the resulting map directly to the
|
||||
* {@code syncBody(Object)} shortcut method in {@code WebClient}.
|
||||
*
|
||||
* @param name the part name
|
||||
* @param publisher the publisher that forms the part value
|
||||
* @param typeReference the type contained in the {@code publisher}
|
||||
* @return a {@code FormInserter} that can writes the provided multipart
|
||||
* data and also allows adding more parts
|
||||
* @return the inserter that allows adding more parts
|
||||
*/
|
||||
public static <T, P extends Publisher<T>> MultipartInserter fromMultipartAsyncData(String key,
|
||||
public static <T, P extends Publisher<T>> MultipartInserter fromMultipartAsyncData(String name,
|
||||
P publisher, ParameterizedTypeReference<T> typeReference) {
|
||||
|
||||
Assert.notNull(key, "'key' must not be null");
|
||||
Assert.notNull(name, "'key' must not be null");
|
||||
Assert.notNull(publisher, "'publisher' must not be null");
|
||||
Assert.notNull(typeReference, "'typeReference' must not be null");
|
||||
|
||||
return new DefaultMultipartInserter().withPublisher(key, publisher, typeReference);
|
||||
return new DefaultMultipartInserter().withPublisher(name, publisher, typeReference);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -375,26 +376,25 @@ public abstract class BodyInserters {
|
|||
|
||||
|
||||
/**
|
||||
* Sub-interface of {@link BodyInserter} that allows for additional (multipart) form data to be
|
||||
* added.
|
||||
* Extension of {@link BodyInserter} that allows for adding form data or
|
||||
* multipart form data.
|
||||
*/
|
||||
// Note that FormInserter is parameterized to ClientHttpRequest, not ReactiveHttpOutputMessage
|
||||
// like other return values methods, since sending form data only typically happens on the client-side
|
||||
public interface FormInserter<T> extends
|
||||
BodyInserter<MultiValueMap<String, T>, ClientHttpRequest> {
|
||||
public interface FormInserter<T> extends BodyInserter<MultiValueMap<String, T>, ClientHttpRequest> {
|
||||
|
||||
// FormInserter is parameterized to ClientHttpRequest (for client-side use only)
|
||||
|
||||
/**
|
||||
* Adds the specified key-value pair to the form.
|
||||
* @param key the key to be added
|
||||
* @param value the value to be added
|
||||
* @return this inserter
|
||||
* @return this inserter for adding more parts
|
||||
*/
|
||||
FormInserter<T> with(String key, @Nullable T value);
|
||||
|
||||
/**
|
||||
* Adds the specified values to the form.
|
||||
* @param values the values to be added
|
||||
* @return this inserter
|
||||
* @return this inserter for adding more parts
|
||||
*/
|
||||
FormInserter<T> with(MultiValueMap<String, T> values);
|
||||
|
||||
|
|
@ -402,30 +402,30 @@ public abstract class BodyInserters {
|
|||
|
||||
|
||||
/**
|
||||
* Extension of {@link FormInserter} that has methods for adding asynchronous part data.
|
||||
* Extension of {@link FormInserter} that allows for adding asynchronous parts.
|
||||
*/
|
||||
public interface MultipartInserter extends FormInserter<Object> {
|
||||
|
||||
/**
|
||||
* Adds the specified publisher as a part.
|
||||
*
|
||||
* @param key the key to be added
|
||||
* @param publisher the publisher to be added as value
|
||||
* @param elementClass the class of elements contained in {@code publisher}
|
||||
* @return this inserter
|
||||
* Add an asynchronous part with {@link Publisher}-based content.
|
||||
* @param name the name of the part to add
|
||||
* @param publisher the part contents
|
||||
* @param elementClass the type of elements contained in the publisher
|
||||
* @return this inserter for adding more parts
|
||||
*/
|
||||
<T, P extends Publisher<T>> MultipartInserter withPublisher(String key, P publisher,
|
||||
<T, P extends Publisher<T>> MultipartInserter withPublisher(String name, P publisher,
|
||||
Class<T> elementClass);
|
||||
|
||||
/**
|
||||
* Adds the specified publisher as a part.
|
||||
*
|
||||
* @param key the key to be added
|
||||
* Variant of {@link #withPublisher(String, Publisher, Class)} that accepts a
|
||||
* {@link ParameterizedTypeReference} for the element type, which allows
|
||||
* specifying generic type information.
|
||||
* @param name the key to be added
|
||||
* @param publisher the publisher to be added as value
|
||||
* @param typeReference the type of elements contained in {@code publisher}
|
||||
* @return this inserter
|
||||
* @return this inserter for adding more parts
|
||||
*/
|
||||
<T, P extends Publisher<T>> MultipartInserter withPublisher(String key, P publisher,
|
||||
<T, P extends Publisher<T>> MultipartInserter withPublisher(String name, P publisher,
|
||||
ParameterizedTypeReference<T> typeReference);
|
||||
|
||||
}
|
||||
|
|
@ -435,9 +435,11 @@ public abstract class BodyInserters {
|
|||
|
||||
private final MultiValueMap<String, String> data = new LinkedMultiValueMap<>();
|
||||
|
||||
|
||||
public DefaultFormInserter() {
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public FormInserter<String> with(String key, @Nullable String value) {
|
||||
this.data.add(key, value);
|
||||
|
|
@ -465,9 +467,11 @@ public abstract class BodyInserters {
|
|||
|
||||
private final MultipartBodyBuilder builder = new MultipartBodyBuilder();
|
||||
|
||||
|
||||
public DefaultMultipartInserter() {
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public MultipartInserter with(String key, @Nullable Object value) {
|
||||
Assert.notNull(value, "'value' must not be null");
|
||||
|
|
@ -492,18 +496,18 @@ public abstract class BodyInserters {
|
|||
}
|
||||
|
||||
@Override
|
||||
public <T, P extends Publisher<T>> MultipartInserter withPublisher(String key,
|
||||
public <T, P extends Publisher<T>> MultipartInserter withPublisher(String name,
|
||||
P publisher, Class<T> elementClass) {
|
||||
|
||||
this.builder.asyncPart(key, publisher, elementClass);
|
||||
this.builder.asyncPart(name, publisher, elementClass);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T, P extends Publisher<T>> MultipartInserter withPublisher(String key,
|
||||
public <T, P extends Publisher<T>> MultipartInserter withPublisher(String name,
|
||||
P publisher, ParameterizedTypeReference<T> typeReference) {
|
||||
|
||||
this.builder.asyncPart(key, publisher, typeReference);
|
||||
this.builder.asyncPart(name, publisher, typeReference);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue