From a1c24d212223642ac0e39602049016c7ae65eb30 Mon Sep 17 00:00:00 2001 From: Rossen Stoyanchev Date: Wed, 8 Mar 2017 17:13:40 -0500 Subject: [PATCH] SSE reader support to read full content as a String The SSE reader is ordered ahead of StringDecoder because with response.decodeToFlux(String.class) we actually want the SSE reader to get involved first based on the content-type. At the same time with response.decodeToMono(String.class) there is nothing the SSE reader can do while the StringDecoder could read the entore content as one String, as long as the server does terminate the stream which can happen in a testing scenario. This commit updates ServerSentEventHttpMessageReader#readMono in to support String.class by delegating to StringDecoder. Since reading to a Mono is an explicit choice there is not much possibility for interfering with decoding to Flux. Issue: SPR-15331 --- .../codec/ServerSentEventHttpMessageReader.java | 10 ++++++++++ .../ServerSentEventHttpMessageReaderTests.java | 15 +++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/spring-web/src/main/java/org/springframework/http/codec/ServerSentEventHttpMessageReader.java b/spring-web/src/main/java/org/springframework/http/codec/ServerSentEventHttpMessageReader.java index a16063d1b5..ee9f4ffc9a 100644 --- a/spring-web/src/main/java/org/springframework/http/codec/ServerSentEventHttpMessageReader.java +++ b/spring-web/src/main/java/org/springframework/http/codec/ServerSentEventHttpMessageReader.java @@ -31,6 +31,7 @@ import reactor.core.publisher.Mono; import org.springframework.core.ResolvableType; import org.springframework.core.codec.CodecException; import org.springframework.core.codec.Decoder; +import org.springframework.core.codec.StringDecoder; import org.springframework.core.io.buffer.DataBuffer; import org.springframework.core.io.buffer.DataBufferFactory; import org.springframework.core.io.buffer.DataBufferUtils; @@ -57,6 +58,8 @@ public class ServerSentEventHttpMessageReader implements HttpMessageReader> dataDecoders; @@ -178,6 +181,13 @@ public class ServerSentEventHttpMessageReader implements HttpMessageReader readMono(ResolvableType elementType, ReactiveHttpInputMessage inputMessage, Map hints) { + // Let's give StringDecoder a chance since SSE is ordered ahead of it + + if (String.class.equals(elementType.getRawClass())) { + Flux body = inputMessage.getBody(); + return stringDecoder.decodeToMono(body, elementType, null, null).cast(Object.class); + } + return Mono.error(new UnsupportedOperationException( "ServerSentEventHttpMessageReader only supports reading stream of events as a Flux")); } diff --git a/spring-web/src/test/java/org/springframework/http/codec/ServerSentEventHttpMessageReaderTests.java b/spring-web/src/test/java/org/springframework/http/codec/ServerSentEventHttpMessageReaderTests.java index dd725b4252..56dd5a1eea 100644 --- a/spring-web/src/test/java/org/springframework/http/codec/ServerSentEventHttpMessageReaderTests.java +++ b/spring-web/src/test/java/org/springframework/http/codec/ServerSentEventHttpMessageReaderTests.java @@ -21,6 +21,7 @@ import java.util.Collections; import org.junit.Test; import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; import reactor.test.StepVerifier; import org.springframework.core.ResolvableType; @@ -157,4 +158,18 @@ public class ServerSentEventHttpMessageReaderTests extends AbstractDataBufferAll .verify(); } + @Test // SPR-15331 + public void decodeFullContentAsString() { + + String body = "data:foo\ndata:bar\n\ndata:baz\n\n"; + MockServerHttpRequest request = MockServerHttpRequest.post("/").body(body); + + String actual = messageReader + .readMono(ResolvableType.forClass(String.class), request, Collections.emptyMap()) + .cast(String.class) + .block(Duration.ZERO); + + assertEquals(body, actual); + } + }