Support @RequestBody Flux<Part> in WebFlux

This commit turns the Synchronoss NIO Multipart HttpMessageReader into
a reader of Flux<Part> and creates a separate reader that aggregates
the parts into a MultiValueMap<String, Part>.

Issue: SPR-14546
This commit is contained in:
Rossen Stoyanchev
2017-05-03 17:25:49 -04:00
parent d43dfc7bae
commit b5089ac092
9 changed files with 198 additions and 57 deletions

View File

@@ -41,7 +41,8 @@ import org.springframework.core.io.buffer.DefaultDataBufferFactory;
import org.springframework.http.MediaType;
import org.springframework.http.codec.json.Jackson2JsonDecoder;
import org.springframework.http.codec.json.Jackson2JsonEncoder;
import org.springframework.http.codec.multipart.SynchronossMultipartHttpMessageReader;
import org.springframework.http.codec.multipart.MultipartHttpMessageReader;
import org.springframework.http.codec.multipart.SynchronossPartHttpMessageReader;
import org.springframework.http.codec.xml.Jaxb2XmlDecoder;
import org.springframework.http.codec.xml.Jaxb2XmlEncoder;
import org.springframework.util.MimeTypeUtils;
@@ -63,14 +64,15 @@ public class ServerCodecConfigurerTests {
@Test
public void defaultReaders() throws Exception {
List<HttpMessageReader<?>> readers = this.configurer.getReaders();
assertEquals(10, readers.size());
assertEquals(11, readers.size());
assertEquals(ByteArrayDecoder.class, getNextDecoder(readers).getClass());
assertEquals(ByteBufferDecoder.class, getNextDecoder(readers).getClass());
assertEquals(DataBufferDecoder.class, getNextDecoder(readers).getClass());
assertEquals(ResourceDecoder.class, getNextDecoder(readers).getClass());
assertStringDecoder(getNextDecoder(readers), true);
assertEquals(FormHttpMessageReader.class, readers.get(this.index.getAndIncrement()).getClass());
assertEquals(SynchronossMultipartHttpMessageReader.class, readers.get(this.index.getAndIncrement()).getClass());
assertEquals(SynchronossPartHttpMessageReader.class, readers.get(this.index.getAndIncrement()).getClass());
assertEquals(MultipartHttpMessageReader.class, readers.get(this.index.getAndIncrement()).getClass());
assertEquals(Jaxb2XmlDecoder.class, getNextDecoder(readers).getClass());
assertEquals(Jackson2JsonDecoder.class, getNextDecoder(readers).getClass());
assertStringDecoder(getNextDecoder(readers), false);

View File

@@ -102,7 +102,9 @@ public class MultipartHttpMessageWriterTests {
assertNotNull("No boundary found", contentType.getParameter("boundary"));
// see if Synchronoss NIO Multipart can read what we wrote
SynchronossMultipartHttpMessageReader reader = new SynchronossMultipartHttpMessageReader();
SynchronossPartHttpMessageReader synchronossReader = new SynchronossPartHttpMessageReader();
MultipartHttpMessageReader reader = new MultipartHttpMessageReader(synchronossReader);
MockServerHttpRequest request = MockServerHttpRequest.post("/foo")
.header(HttpHeaders.CONTENT_TYPE, contentType.toString())
.body(response.getBody());

View File

@@ -32,53 +32,57 @@ import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.MockHttpOutputMessage;
import org.springframework.http.codec.HttpMessageReader;
import org.springframework.http.converter.FormHttpMessageConverter;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.mock.http.server.reactive.test.MockServerHttpRequest;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import static java.util.Collections.*;
import static org.junit.Assert.*;
import static org.springframework.http.HttpHeaders.*;
import static org.springframework.http.MediaType.*;
import static java.util.Collections.emptyMap;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.springframework.core.ResolvableType.forClassWithGenerics;
import static org.springframework.http.HttpHeaders.CONTENT_LENGTH;
import static org.springframework.http.HttpHeaders.CONTENT_TYPE;
import static org.springframework.http.MediaType.MULTIPART_FORM_DATA;
/**
* @author Sebastien Deleuze
*/
public class SynchronossMultipartHttpMessageReaderTests {
public class SynchronossPartHttpMessageReaderTests {
private final HttpMessageReader<MultiValueMap<String, Part>> reader = new SynchronossMultipartHttpMessageReader();
private final MultipartHttpMessageReader reader =
new MultipartHttpMessageReader(new SynchronossPartHttpMessageReader());
@Test
public void canRead() {
assertTrue(this.reader.canRead(
ResolvableType.forClassWithGenerics(MultiValueMap.class, String.class, Part.class),
forClassWithGenerics(MultiValueMap.class, String.class, Part.class),
MediaType.MULTIPART_FORM_DATA));
assertFalse(this.reader.canRead(
ResolvableType.forClassWithGenerics(MultiValueMap.class, String.class, Object.class),
forClassWithGenerics(MultiValueMap.class, String.class, Object.class),
MediaType.MULTIPART_FORM_DATA));
assertFalse(this.reader.canRead(
ResolvableType.forClassWithGenerics(MultiValueMap.class, String.class, String.class),
forClassWithGenerics(MultiValueMap.class, String.class, String.class),
MediaType.MULTIPART_FORM_DATA));
assertFalse(this.reader.canRead(
ResolvableType.forClassWithGenerics(Map.class, String.class, String.class),
forClassWithGenerics(Map.class, String.class, String.class),
MediaType.MULTIPART_FORM_DATA));
assertFalse(this.reader.canRead(
ResolvableType.forClassWithGenerics(MultiValueMap.class, String.class, Part.class),
forClassWithGenerics(MultiValueMap.class, String.class, Part.class),
MediaType.APPLICATION_FORM_URLENCODED));
}
@Test
public void resolveParts() throws IOException {
ServerHttpRequest request = generateMultipartRequest();
ResolvableType elementType = ResolvableType.forClassWithGenerics(MultiValueMap.class, String.class, Part.class);
ResolvableType elementType = forClassWithGenerics(MultiValueMap.class, String.class, Part.class);
MultiValueMap<String, Part> parts = this.reader.readMono(elementType, request, emptyMap()).block();
assertEquals(2, parts.size());
@@ -105,7 +109,7 @@ public class SynchronossMultipartHttpMessageReaderTests {
@Test
public void bodyError() {
ServerHttpRequest request = generateErrorMultipartRequest();
ResolvableType elementType = ResolvableType.forClassWithGenerics(MultiValueMap.class, String.class, Part.class);
ResolvableType elementType = forClassWithGenerics(MultiValueMap.class, String.class, Part.class);
StepVerifier.create(this.reader.readMono(elementType, request, emptyMap())).verifyError();
}