From 60e5abff7f65b1cceb006e9ed35561b15b6e14e7 Mon Sep 17 00:00:00 2001 From: Brian Clozel Date: Fri, 4 Sep 2026 16:21:13 +0200 Subject: [PATCH] Enforce "data: " prefix for outgoing SSE data payloads Prior to this commit, SSE support in Spring would write payloads with the "data:" prefix (without space). While this is OK with the standard, this makes it harder for implementations to support reading and writing payloads with Spring (the round trip use case). This commit introduces a breaking change and now enforces "data: " in all variants. This has the potential of breaking some low level test suites with text/plain or custom media types, but this should overall make the situation better for developers. Closes gh-37242 --- .../standalone/ReactiveReturnTypeTests.java | 2 +- .../http/codec/ServerSentEvent.java | 4 +-- .../http/codec/json/Jackson2JsonEncoder.java | 2 +- .../http/codec/json/JacksonJsonEncoder.java | 2 +- .../AbstractJacksonHttpMessageConverter.java | 2 +- .../AbstractJackson2HttpMessageConverter.java | 2 +- .../springframework/web/util/SseUtils.java | 8 ++--- ...ServerSentEventHttpMessageWriterTests.java | 36 +++++++++---------- .../http/codec/ServerSentEventTests.java | 2 +- .../JacksonJsonHttpMessageConverterTests.java | 2 +- ...pingJackson2HttpMessageConverterTests.java | 2 +- .../web/util/SseUtilsTests.java | 4 +-- .../view/ViewResolutionResultHandler.java | 2 +- ...gmentViewResolutionResultHandlerTests.java | 32 ++++++++--------- .../servlet/function/SseServerResponse.java | 5 ++- .../mvc/method/annotation/SseEmitter.java | 2 +- .../function/SseServerResponseTests.java | 16 ++++----- .../FragmentRenderingStreamTests.java | 32 ++++++++--------- .../annotation/ReactiveTypeHandlerTests.java | 6 ++-- .../RequestMappingHandlerAdapterTests.java | 2 +- ...nseBodyEmitterReturnValueHandlerTests.java | 10 +++--- .../method/annotation/SseEmitterTests.java | 26 +++++++------- 22 files changed, 102 insertions(+), 99 deletions(-) diff --git a/spring-test/src/test/java/org/springframework/test/web/servlet/samples/standalone/ReactiveReturnTypeTests.java b/spring-test/src/test/java/org/springframework/test/web/servlet/samples/standalone/ReactiveReturnTypeTests.java index 5d310bb3f6e..f4b4d0564f9 100644 --- a/spring-test/src/test/java/org/springframework/test/web/servlet/samples/standalone/ReactiveReturnTypeTests.java +++ b/spring-test/src/test/java/org/springframework/test/web/servlet/samples/standalone/ReactiveReturnTypeTests.java @@ -52,7 +52,7 @@ class ReactiveReturnTypeTests { .andReturn(); mockMvc.perform(asyncDispatch(mvcResult)) - .andExpect(content().string("data:event0\n\ndata:event1\n\ndata:event2\n\n")); + .andExpect(content().string("data: event0\n\ndata: event1\n\ndata: event2\n\n")); } diff --git a/spring-web/src/main/java/org/springframework/http/codec/ServerSentEvent.java b/spring-web/src/main/java/org/springframework/http/codec/ServerSentEvent.java index e77f3b8a08b..87ea1c62133 100644 --- a/spring-web/src/main/java/org/springframework/http/codec/ServerSentEvent.java +++ b/spring-web/src/main/java/org/springframework/http/codec/ServerSentEvent.java @@ -96,7 +96,7 @@ public final class ServerSentEvent { /** * Return a StringBuilder with the id, event, retry, and comment fields fully - * serialized, and also appending "data:" if there is data. + * serialized, and also appending "data: " if there is data. * @since 6.2.1 */ public String format() { @@ -116,7 +116,7 @@ public final class ServerSentEvent { sb.append('\n'); } if (this.data != null) { - sb.append("data:"); + sb.append("data: "); } return sb.toString(); } diff --git a/spring-web/src/main/java/org/springframework/http/codec/json/Jackson2JsonEncoder.java b/spring-web/src/main/java/org/springframework/http/codec/json/Jackson2JsonEncoder.java index 274780fda31..b1f2b19e957 100644 --- a/spring-web/src/main/java/org/springframework/http/codec/json/Jackson2JsonEncoder.java +++ b/spring-web/src/main/java/org/springframework/http/codec/json/Jackson2JsonEncoder.java @@ -69,7 +69,7 @@ public class Jackson2JsonEncoder extends AbstractJackson2Encoder { private static PrettyPrinter initSsePrettyPrinter() { DefaultPrettyPrinter printer = new DefaultPrettyPrinter(); - printer.indentObjectsWith(new DefaultIndenter(" ", "\ndata:")); + printer.indentObjectsWith(new DefaultIndenter(" ", "\ndata: ")); return printer; } diff --git a/spring-web/src/main/java/org/springframework/http/codec/json/JacksonJsonEncoder.java b/spring-web/src/main/java/org/springframework/http/codec/json/JacksonJsonEncoder.java index 9caf6aba742..9ac9a989d2e 100644 --- a/spring-web/src/main/java/org/springframework/http/codec/json/JacksonJsonEncoder.java +++ b/spring-web/src/main/java/org/springframework/http/codec/json/JacksonJsonEncoder.java @@ -117,7 +117,7 @@ public class JacksonJsonEncoder extends AbstractJacksonEncoder { private static PrettyPrinter initSsePrettyPrinter() { DefaultPrettyPrinter printer = new DefaultPrettyPrinter(); - printer.indentObjectsWith(new DefaultIndenter(" ", "\ndata:")); + printer.indentObjectsWith(new DefaultIndenter(" ", "\ndata: ")); return printer; } diff --git a/spring-web/src/main/java/org/springframework/http/converter/AbstractJacksonHttpMessageConverter.java b/spring-web/src/main/java/org/springframework/http/converter/AbstractJacksonHttpMessageConverter.java index b9f730f0dcf..2005351bcee 100644 --- a/spring-web/src/main/java/org/springframework/http/converter/AbstractJacksonHttpMessageConverter.java +++ b/spring-web/src/main/java/org/springframework/http/converter/AbstractJacksonHttpMessageConverter.java @@ -175,7 +175,7 @@ public abstract class AbstractJacksonHttpMessageConverter { String value = dataBuffer.toString(charset); DataBufferUtils.release(dataBuffer); - assertThat(value).isEqualTo("data:\u00A3\n\n"); + assertThat(value).isEqualTo("data: \u00A3\n\n"); }) .expectComplete() .verify(); @@ -151,10 +151,10 @@ class ServerSentEventHttpMessageWriterTests extends AbstractDataBufferAllocating testWrite(source, outputMessage, Pojo.class); StepVerifier.create(outputMessage.getBody()) - .consumeNextWith(stringConsumer("data:")) + .consumeNextWith(stringConsumer("data: ")) .consumeNextWith(stringConsumer("{\"foo\":\"foofoo\",\"bar\":\"barbar\"}")) .consumeNextWith(stringConsumer("\n\n")) - .consumeNextWith(stringConsumer("data:")) + .consumeNextWith(stringConsumer("data: ")) .consumeNextWith(stringConsumer("{\"foo\":\"foofoofoo\",\"bar\":\"barbarbar\"}")) .consumeNextWith(stringConsumer("\n\n")) .expectComplete() @@ -173,19 +173,19 @@ class ServerSentEventHttpMessageWriterTests extends AbstractDataBufferAllocating testWrite(source, outputMessage, Pojo.class); StepVerifier.create(outputMessage.getBody()) - .consumeNextWith(stringConsumer("data:")) + .consumeNextWith(stringConsumer("data: ")) .consumeNextWith(stringConsumer(""" { - data: "foo" : "foofoo", - data: "bar" : "barbar" - data:}""")) + data: "foo" : "foofoo", + data: "bar" : "barbar" + data: }""")) .consumeNextWith(stringConsumer("\n\n")) - .consumeNextWith(stringConsumer("data:")) + .consumeNextWith(stringConsumer("data: ")) .consumeNextWith(stringConsumer(""" { - data: "foo" : "foofoofoo", - data: "bar" : "barbarbar" - data:}""")) + data: "foo" : "foofoofoo", + data: "bar" : "barbarbar" + data: }""")) .consumeNextWith(stringConsumer("\n\n")) .expectComplete() .verify(); @@ -203,7 +203,7 @@ class ServerSentEventHttpMessageWriterTests extends AbstractDataBufferAllocating assertThat(outputMessage.getHeaders().getContentType()).isEqualTo(mediaType); StepVerifier.create(outputMessage.getBody()) - .consumeNextWith(stringConsumer("data:", charset)) + .consumeNextWith(stringConsumer("data: ", charset)) .consumeNextWith(stringConsumer("{\"foo\":\"foo\uD834\uDD1E\",\"bar\":\"bar\uD834\uDD1E\"}", charset)) .consumeNextWith(stringConsumer("\n\n", charset)) .expectComplete() diff --git a/spring-web/src/test/java/org/springframework/http/codec/ServerSentEventTests.java b/spring-web/src/test/java/org/springframework/http/codec/ServerSentEventTests.java index 9e1a1d7c76f..1790523458c 100644 --- a/spring-web/src/test/java/org/springframework/http/codec/ServerSentEventTests.java +++ b/spring-web/src/test/java/org/springframework/http/codec/ServerSentEventTests.java @@ -51,7 +51,7 @@ class ServerSentEventTests { void supportMultiLineComments(String newLine, String description) { ServerSentEvent event = ServerSentEvent.builder() .comment("foo" + newLine + "bar" + newLine + "baz").data("payload").build(); - assertThat(event.format()).isEqualTo(":foo\n:bar\n:baz\ndata:"); + assertThat(event.format()).isEqualTo(":foo\n:bar\n:baz\ndata: "); } private static Stream newLineCharacters() { diff --git a/spring-web/src/test/java/org/springframework/http/converter/json/JacksonJsonHttpMessageConverterTests.java b/spring-web/src/test/java/org/springframework/http/converter/json/JacksonJsonHttpMessageConverterTests.java index 66964c9f140..f19cec8015d 100644 --- a/spring-web/src/test/java/org/springframework/http/converter/json/JacksonJsonHttpMessageConverterTests.java +++ b/spring-web/src/test/java/org/springframework/http/converter/json/JacksonJsonHttpMessageConverterTests.java @@ -415,7 +415,7 @@ class JacksonJsonHttpMessageConverterTests { MediaType.APPLICATION_JSON, outputMessage, null); String result = outputMessage.getBodyAsString(StandardCharsets.UTF_8); - assertThat(result).isEqualTo("{\ndata: \"name\" : \"Jason\"\ndata:}"); + assertThat(result).isEqualTo("{\ndata: \"name\" : \"Jason\"\ndata: }"); } @Test diff --git a/spring-web/src/test/java/org/springframework/http/converter/json/MappingJackson2HttpMessageConverterTests.java b/spring-web/src/test/java/org/springframework/http/converter/json/MappingJackson2HttpMessageConverterTests.java index 2d570301278..f9dcda30ed4 100644 --- a/spring-web/src/test/java/org/springframework/http/converter/json/MappingJackson2HttpMessageConverterTests.java +++ b/spring-web/src/test/java/org/springframework/http/converter/json/MappingJackson2HttpMessageConverterTests.java @@ -385,7 +385,7 @@ class MappingJackson2HttpMessageConverterTests { this.converter.writeInternal(bean, null, outputMessage); String result = outputMessage.getBodyAsString(StandardCharsets.UTF_8); - assertThat(result).isEqualTo("{\ndata: \"name\" : \"Jason\"\ndata:}"); + assertThat(result).isEqualTo("{\ndata: \"name\" : \"Jason\"\ndata: }"); } @Test diff --git a/spring-web/src/test/java/org/springframework/web/util/SseUtilsTests.java b/spring-web/src/test/java/org/springframework/web/util/SseUtilsTests.java index 94a649a0e2d..77b43781da6 100644 --- a/spring-web/src/test/java/org/springframework/web/util/SseUtilsTests.java +++ b/spring-web/src/test/java/org/springframework/web/util/SseUtilsTests.java @@ -44,9 +44,9 @@ class SseUtilsTests { @MethodSource("newLineCharacters") void appendFieldValueReplacesLineSeparatorWithFieldPrefix(String newLine, String description) { StringBuilder sb = new StringBuilder(); - sb.append("data:"); + sb.append("data: "); SseUtils.appendFieldValue("data", "first" + newLine + "second", sb); - assertThat(sb).hasToString("data:first\ndata:second"); + assertThat(sb).hasToString("data: first\ndata: second"); } @ParameterizedTest(name = "{1}") diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/result/view/ViewResolutionResultHandler.java b/spring-webflux/src/main/java/org/springframework/web/reactive/result/view/ViewResolutionResultHandler.java index b0a7c0e41df..c2502081db4 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/result/view/ViewResolutionResultHandler.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/result/view/ViewResolutionResultHandler.java @@ -590,7 +590,7 @@ public class ViewResolutionResultHandler extends HandlerResultHandlerSupport imp ServerSentEvent sse = (ServerSentEvent) hints; CharSequence eventText = (sse != null ? sse.format() : - (fragment.viewName() != null ? "event:" + fragment.viewName() + "\n" : "") + "data:"); + (fragment.viewName() != null ? "event:" + fragment.viewName() + "\n" : "") + "data: "); DataBuffer prefix = encodeText(eventText.toString(), charset, bufferFactory); DataBuffer suffix = encodeText("\n\n", charset, bufferFactory); diff --git a/spring-webflux/src/test/java/org/springframework/web/reactive/result/view/FragmentViewResolutionResultHandlerTests.java b/spring-webflux/src/test/java/org/springframework/web/reactive/result/view/FragmentViewResolutionResultHandlerTests.java index db95230fc13..74deefb5e4a 100644 --- a/spring-webflux/src/test/java/org/springframework/web/reactive/result/view/FragmentViewResolutionResultHandlerTests.java +++ b/spring-webflux/src/test/java/org/springframework/web/reactive/result/view/FragmentViewResolutionResultHandlerTests.java @@ -107,14 +107,14 @@ class FragmentViewResolutionResultHandlerTests { on(Handler.class).resolveReturnType(Flux.class, Fragment.class), """ event:fragment1 - data:

- data: Hello Foo - data:

+ data:

+ data: Hello Foo + data:

event:fragment2 - data:

- data: Hello Bar - data:

+ data:

+ data: Hello Bar + data:

"""); } @@ -126,10 +126,10 @@ class FragmentViewResolutionResultHandlerTests { on(Handler.class).resolveReturnType(Flux.class, Fragment.class), """ event:fragment1 - data:

- data: Hello Foo - data: and Bar - data:

+ data:

+ data: Hello Foo + data: and Bar + data:

"""); } @@ -147,15 +147,15 @@ class FragmentViewResolutionResultHandlerTests { """ id:id1 event:event1 - data:

- data: Hello Foo - data:

+ data:

+ data: Hello Foo + data:

id:id2 event:event2 - data:

- data: Hello Bar - data:

+ data:

+ data: Hello Bar + data:

"""); } diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/function/SseServerResponse.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/function/SseServerResponse.java index 52f6b6f6523..8064ebe5ebb 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/function/SseServerResponse.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/function/SseServerResponse.java @@ -177,6 +177,9 @@ final class SseServerResponse extends AbstractServerResponse { private SseBuilder field(String name, String value) { this.builder.append(name).append(':'); + if (!name.isEmpty()) { + this.builder.append(' '); + } SseUtils.appendFieldValue(name, value, this.builder); this.builder.append('\n'); return this; @@ -200,7 +203,7 @@ final class SseServerResponse extends AbstractServerResponse { @SuppressWarnings("unchecked") private void writeObject(Object data) throws IOException { - this.builder.append("data:"); + this.builder.append("data: "); try { this.outputMessage.getBody().write(builderBytes()); Class dataClass = data.getClass(); diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/SseEmitter.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/SseEmitter.java index 42ba09c6855..22b4adf83e8 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/SseEmitter.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/SseEmitter.java @@ -240,7 +240,7 @@ public class SseEmitter extends ResponseBodyEmitter { if (object instanceof ModelAndView mav && !this.hasName && mav.getViewName() != null) { name(mav.getViewName()); } - append("data:"); + append("data: "); saveAppendedText(TEXT_PLAIN); if (object instanceof String text) { writeStringData(text, mediaType); diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/function/SseServerResponseTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/function/SseServerResponseTests.java index b95da1ab4e9..4c08bb652a3 100644 --- a/spring-webmvc/src/test/java/org/springframework/web/servlet/function/SseServerResponseTests.java +++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/function/SseServerResponseTests.java @@ -71,7 +71,7 @@ class SseServerResponseTests { ModelAndView mav = response.writeTo(this.mockRequest, this.mockResponse, context); assertThat(mav).isNull(); - String expected = "data:" + body + "\n\n"; + String expected = "data: " + body + "\n\n"; assertThat(this.mockResponse.getContentAsString()).isEqualTo(expected); } @@ -127,7 +127,7 @@ class SseServerResponseTests { ModelAndView mav = response.writeTo(this.mockRequest, this.mockResponse, context); assertThat(mav).isNull(); - String expected = "data:{\"name\":\"John Doe\",\"age\":42}\n\n"; + String expected = "data: {\"name\":\"John Doe\",\"age\":42}\n\n"; assertThat(this.mockResponse.getContentAsString()).isEqualTo(expected); } @@ -151,10 +151,10 @@ class SseServerResponseTests { assertThat(mav).isNull(); String expected = """ - data:{ - data: "name" : "John Doe", - data: "age" : 42 - data:} + data: { + data: "name" : "John Doe", + data: "age" : 42 + data: } """; assertThat(this.mockResponse.getContentAsString()).isEqualTo(expected); @@ -186,7 +186,7 @@ class SseServerResponseTests { :comment line 1 :comment line 2 retry:1000 - data:data + data: data """; assertThat(this.mockResponse.getContentAsString()).isEqualTo(expected); @@ -229,7 +229,7 @@ class SseServerResponseTests { ModelAndView mav = response.writeTo(this.mockRequest, this.mockResponse, context); assertThat(mav).isNull(); - String expected = "data:line1\ndata:line2\ndata:line3\n\n"; + String expected = "data: line1\ndata: line2\ndata: line3\n\n"; assertThat(this.mockResponse.getContentAsString()).isEqualTo(expected); } diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/FragmentRenderingStreamTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/FragmentRenderingStreamTests.java index f478dd9dfa9..f34e55fca1a 100644 --- a/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/FragmentRenderingStreamTests.java +++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/FragmentRenderingStreamTests.java @@ -104,14 +104,14 @@ class FragmentRenderingStreamTests { assertThat(this.response.getContentType()).isEqualTo("text/event-stream"); assertThat(this.response.getContentAsString()).isEqualTo((""" event:fragment1 - data:

- data: Hello Foo - data:

+ data:

+ data: Hello Foo + data:

event:fragment2 - data:

- data: Hello Bar - data:

+ data:

+ data: Hello Bar + data:

""")); } @@ -134,14 +134,14 @@ class FragmentRenderingStreamTests { assertThat(this.response.getContentType()).isEqualTo("text/event-stream"); assertThat(this.response.getContentAsString()).isEqualTo((""" event:fragment1 - data:

- data: Hello Foo - data:

+ data:

+ data: Hello Foo + data:

event:fragment2 - data:

- data: Hello Bar - data:

+ data:

+ data: Hello Bar + data:

""")); } @@ -163,10 +163,10 @@ class FragmentRenderingStreamTests { assertThat(this.response.getContentType()).isEqualTo("text/event-stream"); assertThat(this.response.getContentAsString()).isEqualTo((""" event:fragment1 - data:

- data: Hello Foo - data: and Bar - data:

+ data:

+ data: Hello Foo + data: and Bar + data:

""")); } diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ReactiveTypeHandlerTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ReactiveTypeHandlerTests.java index 65e4fd2c1f3..32c031f4238 100644 --- a/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ReactiveTypeHandlerTests.java +++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ReactiveTypeHandlerTests.java @@ -267,7 +267,7 @@ class ReactiveTypeHandlerTests { sink.tryEmitNext("baz"); sink.tryEmitComplete(); - assertThat(emitterHandler.getValuesAsText()).isEqualTo("data:foo\n\ndata:bar\n\ndata:baz\n\n"); + assertThat(emitterHandler.getValuesAsText()).isEqualTo("data: foo\n\ndata: bar\n\ndata: baz\n\n"); } @Test @@ -286,7 +286,7 @@ class ReactiveTypeHandlerTests { sink.tryEmitNext(ServerSentEvent.builder("baz").id("3").build()); sink.tryEmitComplete(); - assertThat(emitterHandler.getValuesAsText()).isEqualTo("id:1\ndata:foo\n\nid:2\ndata:bar\n\nid:3\ndata:baz\n\n"); + assertThat(emitterHandler.getValuesAsText()).isEqualTo("id:1\ndata: foo\n\nid:2\ndata: bar\n\nid:3\ndata: baz\n\n"); } @ParameterizedTest @@ -453,7 +453,7 @@ class ReactiveTypeHandlerTests { sink.tryEmitComplete(); - assertThat(emitterHandler.getValuesAsText()).isEqualTo("data:emitted value\n\n"); + assertThat(emitterHandler.getValuesAsText()).isEqualTo("data: emitted value\n\n"); assertThat(emitterHandler.getSavedRequest()).isSameAs(this.servletRequest); } finally { diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerAdapterTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerAdapterTests.java index 123168ca25e..9edab27d853 100644 --- a/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerAdapterTests.java +++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerAdapterTests.java @@ -218,7 +218,7 @@ class RequestMappingHandlerAdapterTests { assertThat(this.response.getStatus()).isEqualTo(200); assertThat(this.response.getHeader("Content-Type")).isEqualTo("text/event-stream"); - assertThat(this.response.getContentAsString()).isEqualTo("data:event 1\n\ndata:event 2\n\n"); + assertThat(this.response.getContentAsString()).isEqualTo("data: event 1\n\ndata: event 2\n\n"); } @Test diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ResponseBodyEmitterReturnValueHandlerTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ResponseBodyEmitterReturnValueHandlerTests.java index a4f904aa432..005a0174d71 100644 --- a/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ResponseBodyEmitterReturnValueHandlerTests.java +++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ResponseBodyEmitterReturnValueHandlerTests.java @@ -218,8 +218,8 @@ class ResponseBodyEmitterReturnValueHandlerTests { event:update id:1 retry:5000 - data:{"id":1,"name":"Joe"} - data:{"id":2,"name":"John"} + data: {"id":1,"name":"Joe"} + data: {"id":2,"name":"John"} """)); } @@ -235,7 +235,7 @@ class ResponseBodyEmitterReturnValueHandlerTests { assertThat(this.response.getStatus()).isEqualTo(200); assertThat(this.response.getContentType()).isEqualTo("text/event-stream"); - assertThat(this.response.getContentAsString()).isEqualTo("data:foo\n\ndata:bar\n\ndata:baz\n\n"); + assertThat(this.response.getContentAsString()).isEqualTo("data: foo\n\ndata: bar\n\ndata: baz\n\n"); } @Test @@ -274,7 +274,7 @@ class ResponseBodyEmitterReturnValueHandlerTests { assertThat(this.response.getStatus()).isEqualTo(200); assertThat(this.response.getContentType()).isEqualTo("text/event-stream"); - assertThat(this.response.getContentAsString()).isEqualTo("data:foo123\n\ndata:bar123\n\ndata:baz123\n\n"); + assertThat(this.response.getContentAsString()).isEqualTo("data: foo123\n\ndata: bar123\n\ndata: baz123\n\n"); } @Test // gh-21972 @@ -357,7 +357,7 @@ class ResponseBodyEmitterReturnValueHandlerTests { assertThat(this.request.isAsyncStarted()).isTrue(); assertThat(this.response.getStatus()).isEqualTo(200); assertThat(this.response.getContentType()).isEqualTo("text/event-stream"); - assertThat(this.response.getContentAsString()).isEqualTo("data:foo\n\ndata:bar\n\n"); + assertThat(this.response.getContentAsString()).isEqualTo("data: foo\n\ndata: bar\n\n"); } @Test // gh-36357 diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/SseEmitterTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/SseEmitterTests.java index 2ff5bfebd50..97f7746cbe5 100644 --- a/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/SseEmitterTests.java +++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/SseEmitterTests.java @@ -65,7 +65,7 @@ class SseEmitterTests { void send() throws Exception { this.emitter.send("foo"); this.handler.assertSentObjectCount(3); - this.handler.assertObject(0, "data:", TEXT_PLAIN_UTF8); + this.handler.assertObject(0, "data: ", TEXT_PLAIN_UTF8); this.handler.assertObject(1, "foo"); this.handler.assertObject(2, "\n\n", TEXT_PLAIN_UTF8); this.handler.assertWriteCount(1); @@ -75,7 +75,7 @@ class SseEmitterTests { void sendWithMediaType() throws Exception { this.emitter.send("foo", MediaType.TEXT_PLAIN); this.handler.assertSentObjectCount(3); - this.handler.assertObject(0, "data:", TEXT_PLAIN_UTF8); + this.handler.assertObject(0, "data: ", TEXT_PLAIN_UTF8); this.handler.assertObject(1, "foo", MediaType.TEXT_PLAIN); this.handler.assertObject(2, "\n\n", TEXT_PLAIN_UTF8); this.handler.assertWriteCount(1); @@ -92,7 +92,7 @@ class SseEmitterTests { void sendEventWithDataLine() throws Exception { this.emitter.send(event().data("foo")); this.handler.assertSentObjectCount(3); - this.handler.assertObject(0, "data:", TEXT_PLAIN_UTF8); + this.handler.assertObject(0, "data: ", TEXT_PLAIN_UTF8); this.handler.assertObject(1, "foo"); this.handler.assertObject(2, "\n\n", TEXT_PLAIN_UTF8); this.handler.assertWriteCount(1); @@ -102,9 +102,9 @@ class SseEmitterTests { void sendEventWithTwoDataLines() throws Exception { this.emitter.send(event().data("foo").data("bar")); this.handler.assertSentObjectCount(5); - this.handler.assertObject(0, "data:", TEXT_PLAIN_UTF8); + this.handler.assertObject(0, "data: ", TEXT_PLAIN_UTF8); this.handler.assertObject(1, "foo"); - this.handler.assertObject(2, "\ndata:", TEXT_PLAIN_UTF8); + this.handler.assertObject(2, "\ndata: ", TEXT_PLAIN_UTF8); this.handler.assertObject(3, "bar"); this.handler.assertObject(4, "\n\n", TEXT_PLAIN_UTF8); this.handler.assertWriteCount(1); @@ -115,8 +115,8 @@ class SseEmitterTests { void sendEventWithMultiline(String newLineChars, String description) throws Exception { this.emitter.send(event().data("foo" + newLineChars + "bar" + newLineChars + "baz")); this.handler.assertSentObjectCount(3); - this.handler.assertObject(0, "data:", TEXT_PLAIN_UTF8); - this.handler.assertObject(1, "foo\ndata:bar\ndata:baz"); + this.handler.assertObject(0, "data: ", TEXT_PLAIN_UTF8); + this.handler.assertObject(1, "foo\ndata: bar\ndata: baz"); this.handler.assertObject(2, "\n\n", TEXT_PLAIN_UTF8); this.handler.assertWriteCount(1); } @@ -126,8 +126,8 @@ class SseEmitterTests { void sendEventWithMultilineWithMediaType(String newLineChars, String description) throws Exception { this.emitter.send(event().data("foo" + newLineChars + "bar" + newLineChars + "baz", MediaType.TEXT_PLAIN)); this.handler.assertSentObjectCount(3); - this.handler.assertObject(0, "data:", TEXT_PLAIN_UTF8); - this.handler.assertObject(1, "foo\ndata:bar\ndata:baz", MediaType.TEXT_PLAIN); + this.handler.assertObject(0, "data: ", TEXT_PLAIN_UTF8); + this.handler.assertObject(1, "foo\ndata: bar\ndata: baz", MediaType.TEXT_PLAIN); this.handler.assertObject(2, "\n\n", TEXT_PLAIN_UTF8); this.handler.assertWriteCount(1); } @@ -136,7 +136,7 @@ class SseEmitterTests { void sendEventFull() throws Exception { this.emitter.send(event().comment("blah").name("test").reconnectTime(5000L).id("1").data("foo")); this.handler.assertSentObjectCount(3); - this.handler.assertObject(0, ":blah\nevent:test\nretry:5000\nid:1\ndata:", TEXT_PLAIN_UTF8); + this.handler.assertObject(0, ":blah\nevent:test\nretry:5000\nid:1\ndata: ", TEXT_PLAIN_UTF8); this.handler.assertObject(1, "foo"); this.handler.assertObject(2, "\n\n", TEXT_PLAIN_UTF8); this.handler.assertWriteCount(1); @@ -146,9 +146,9 @@ class SseEmitterTests { void sendEventFullWithTwoDataLinesInTheMiddle() throws Exception { this.emitter.send(event().comment("blah").data("foo").data("bar").name("test").reconnectTime(5000L).id("1")); this.handler.assertSentObjectCount(5); - this.handler.assertObject(0, ":blah\ndata:", TEXT_PLAIN_UTF8); + this.handler.assertObject(0, ":blah\ndata: ", TEXT_PLAIN_UTF8); this.handler.assertObject(1, "foo"); - this.handler.assertObject(2, "\ndata:", TEXT_PLAIN_UTF8); + this.handler.assertObject(2, "\ndata: ", TEXT_PLAIN_UTF8); this.handler.assertObject(3, "bar"); this.handler.assertObject(4, "\nevent:test\nretry:5000\nid:1\n\n", TEXT_PLAIN_UTF8); this.handler.assertWriteCount(1); @@ -173,7 +173,7 @@ class SseEmitterTests { void supportMultiLineComments(String newLineChars, String description) throws Exception { this.emitter.send(event().comment("foo" + newLineChars + "bar" + newLineChars + "baz").data("payload")); this.handler.assertSentObjectCount(3); - this.handler.assertObject(0, ":foo\n:bar\n:baz\ndata:", TEXT_PLAIN_UTF8); + this.handler.assertObject(0, ":foo\n:bar\n:baz\ndata: ", TEXT_PLAIN_UTF8); this.handler.assertObject(1, "payload"); this.handler.assertObject(2, "\n\n", TEXT_PLAIN_UTF8); this.handler.assertWriteCount(1);