Use Mono semantics for JSON object/array serialization
Before this commit, a handler method returning a stream with a JSON content-type was producing a JSON object for single element streams or a JSON array for multiple elements streams. This kind of dynamic change of the output based on the number of elements was difficult to handle on client side and not consistent with Spring MVC behavior. With this commit, we achieve a more consistent behavior by using the Mono semantics to control this behavior. Mono (and Promise/Single) are serialized to JSON object and Flux (and Observable/Stream) are serialized to JSON array.
This commit is contained in:
@@ -18,13 +18,12 @@ package org.springframework.reactive.codec.encoder;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import org.junit.Test;
|
||||
import reactor.Flux;
|
||||
import reactor.Mono;
|
||||
import reactor.io.buffer.Buffer;
|
||||
import reactor.rx.Stream;
|
||||
import reactor.rx.Streams;
|
||||
|
||||
import org.springframework.core.codec.support.JsonObjectEncoder;
|
||||
|
||||
@@ -34,46 +33,59 @@ import org.springframework.core.codec.support.JsonObjectEncoder;
|
||||
public class JsonObjectEncoderTests {
|
||||
|
||||
@Test
|
||||
public void encodeSingleElement() throws InterruptedException {
|
||||
public void encodeSingleElementFlux() throws InterruptedException {
|
||||
JsonObjectEncoder encoder = new JsonObjectEncoder();
|
||||
Stream<ByteBuffer> source = Streams.just(Buffer.wrap("{\"foo\": \"foofoo\", \"bar\": \"barbar\"}").byteBuffer());
|
||||
List<String> results = Streams.from(encoder.encode(source, null, null)).map(chunk -> {
|
||||
Flux<ByteBuffer> source = Flux.just(Buffer.wrap("{\"foo\": \"foofoo\", \"bar\": \"barbar\"}").byteBuffer());
|
||||
Iterable<String> results = Flux.from(encoder.encode(source, null, null)).map(chunk -> {
|
||||
byte[] b = new byte[chunk.remaining()];
|
||||
chunk.get(b);
|
||||
return new String(b, StandardCharsets.UTF_8);
|
||||
}).toList().get();
|
||||
}).toIterable();
|
||||
String result = String.join("", results);
|
||||
assertEquals("[{\"foo\": \"foofoo\", \"bar\": \"barbar\"}]", result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void encodeSingleElementMono() throws InterruptedException {
|
||||
JsonObjectEncoder encoder = new JsonObjectEncoder();
|
||||
Mono<ByteBuffer> source = Mono.just(Buffer.wrap("{\"foo\": \"foofoo\", \"bar\": \"barbar\"}").byteBuffer());
|
||||
Iterable<String> results = Flux.from(encoder.encode(source, null, null)).map(chunk -> {
|
||||
byte[] b = new byte[chunk.remaining()];
|
||||
chunk.get(b);
|
||||
return new String(b, StandardCharsets.UTF_8);
|
||||
}).toIterable();
|
||||
String result = String.join("", results);
|
||||
assertEquals("{\"foo\": \"foofoo\", \"bar\": \"barbar\"}", result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void encodeTwoElements() throws InterruptedException {
|
||||
public void encodeTwoElementsFlux() throws InterruptedException {
|
||||
JsonObjectEncoder encoder = new JsonObjectEncoder();
|
||||
Stream<ByteBuffer> source = Streams.just(
|
||||
Flux<ByteBuffer> source = Flux.just(
|
||||
Buffer.wrap("{\"foo\": \"foofoo\", \"bar\": \"barbar\"}").byteBuffer(),
|
||||
Buffer.wrap("{\"foo\": \"foofoofoo\", \"bar\": \"barbarbar\"}").byteBuffer());
|
||||
List<String> results = Streams.from(encoder.encode(source, null, null)).map(chunk -> {
|
||||
Iterable<String> results = Flux.from(encoder.encode(source, null, null)).map(chunk -> {
|
||||
byte[] b = new byte[chunk.remaining()];
|
||||
chunk.get(b);
|
||||
return new String(b, StandardCharsets.UTF_8);
|
||||
}).toList().get();
|
||||
}).toIterable();
|
||||
String result = String.join("", results);
|
||||
assertEquals("[{\"foo\": \"foofoo\", \"bar\": \"barbar\"},{\"foo\": \"foofoofoo\", \"bar\": \"barbarbar\"}]", result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void encodeThreeElements() throws InterruptedException {
|
||||
public void encodeThreeElementsFlux() throws InterruptedException {
|
||||
JsonObjectEncoder encoder = new JsonObjectEncoder();
|
||||
Stream<ByteBuffer> source = Streams.just(
|
||||
Flux<ByteBuffer> source = Flux.just(
|
||||
Buffer.wrap("{\"foo\": \"foofoo\", \"bar\": \"barbar\"}").byteBuffer(),
|
||||
Buffer.wrap("{\"foo\": \"foofoofoo\", \"bar\": \"barbarbar\"}").byteBuffer(),
|
||||
Buffer.wrap("{\"foo\": \"foofoofoofoo\", \"bar\": \"barbarbarbar\"}").byteBuffer()
|
||||
);
|
||||
List<String> results = Streams.from(encoder.encode(source, null, null)).map(chunk -> {
|
||||
Iterable<String> results = Flux.from(encoder.encode(source, null, null)).map(chunk -> {
|
||||
byte[] b = new byte[chunk.remaining()];
|
||||
chunk.get(b);
|
||||
return new String(b, StandardCharsets.UTF_8);
|
||||
}).toList().get();
|
||||
}).toIterable();
|
||||
String result = String.join("", results);
|
||||
assertEquals("[{\"foo\": \"foofoo\", \"bar\": \"barbar\"},{\"foo\": \"foofoofoo\", \"bar\": \"barbarbar\"},{\"foo\": \"foofoofoofoo\", \"bar\": \"barbarbarbar\"}]", result);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user