Allow Splitting/aggregation operations in Decoders

When decoding buffers as plain strings, the StringDecoder returns a
Publisher that may produce one or more `onNext` events.
This is perfectly valid, but leads to errors when trying to convert the
resulting Publisher into a `reactor.Mono` or `rx.Single`.

If the original Publisher emits 2 or more `onNext` signals,
converting to:
* `rx.Single` will throw an error saying that the underlying Observable
"emitted too many elements"
* `reactor.Mono` may contain only the first emitted element

This commit adds a `AbstractRawByteStreamDecoder` that takes a
`SubscriberBarrier` to apply splitting/aggregation operations on the
received elements.
The `StringDecoder` class now inherits from this abstract class and
uses one of the provided `SubscriberBarrier` implementations to
buffer all received elements in a single buffer.
This commit is contained in:
Brian Clozel
2015-12-15 14:14:00 +01:00
parent 99e51a9101
commit cf6ceeed62
3 changed files with 308 additions and 14 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2002-2016 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.
@@ -16,18 +16,19 @@
package org.springframework.reactive.codec.decoder;
import static java.util.stream.Collectors.*;
import static org.junit.Assert.*;
import java.nio.ByteBuffer;
import java.util.List;
import java.util.stream.StreamSupport;
import static java.util.stream.Collectors.toList;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import org.junit.Test;
import org.reactivestreams.Publisher;
import reactor.Flux;
import reactor.Mono;
import reactor.core.publisher.convert.RxJava1SingleConverter;
import reactor.io.buffer.Buffer;
import rx.Single;
import org.springframework.core.ResolvableType;
import org.springframework.core.codec.support.StringDecoder;
@@ -35,6 +36,7 @@ import org.springframework.http.MediaType;
/**
* @author Sebastien Deleuze
* @author Brian Clozel
*/
public class StringDecoderTests {
@@ -50,11 +52,41 @@ public class StringDecoderTests {
@Test
public void decode() throws InterruptedException {
Flux<ByteBuffer> source = Flux.just(Buffer.wrap("foo").byteBuffer(), Buffer.wrap("bar").byteBuffer());
Flux<String> output = decoder.decode(source, ResolvableType.forClassWithGenerics(Publisher.class, String.class), null);
Flux<String> output = this.decoder.decode(source, ResolvableType.forClassWithGenerics(Flux.class, String.class), null);
List<String> results = StreamSupport.stream(output.toIterable().spliterator(), false).collect(toList());
assertEquals(1, results.size());
assertEquals("foobar", results.get(0));
}
@Test
public void decodeDoNotBuffer() throws InterruptedException {
StringDecoder decoder = new StringDecoder(false);
Flux<ByteBuffer> source = Flux.just(Buffer.wrap("foo").byteBuffer(), Buffer.wrap("bar").byteBuffer());
Flux<String> output = decoder.decode(source, ResolvableType.forClassWithGenerics(Flux.class, String.class), null);
List<String> results = StreamSupport.stream(output.toIterable().spliterator(), false).collect(toList());
assertEquals(2, results.size());
assertEquals("foo", results.get(0));
assertEquals("bar", results.get(1));
}
@Test
public void decodeMono() throws InterruptedException {
Flux<ByteBuffer> source = Flux.just(Buffer.wrap("foo").byteBuffer(), Buffer.wrap("bar").byteBuffer());
Mono<String> mono = Mono.from(this.decoder.decode(source,
ResolvableType.forClassWithGenerics(Mono.class, String.class),
MediaType.TEXT_PLAIN));
String result = mono.get();
assertEquals("foobar", result);
}
@Test
public void decodeSingle() throws InterruptedException {
Flux<ByteBuffer> source = Flux.just(Buffer.wrap("foo").byteBuffer(), Buffer.wrap("bar").byteBuffer());
Single<String> single = RxJava1SingleConverter.from(this.decoder.decode(source,
ResolvableType.forClassWithGenerics(Single.class, String.class),
MediaType.TEXT_PLAIN));
String result = single.toBlocking().value();
assertEquals("foobar", result);
}
}