Skip to content

ServerSentEventHttpMessageReader should process empty data lines #35412

@margarita-sk

Description

@margarita-sk

Spring version: 6.2.10

We utilize Spring's SSE implementation to receive events from a third-party source and stream them to other components.
We noticed that ServerSentEventHttpMessageWriter and ServerSentEventHttpMessageReader are not consistent: data that is serialized cannot be deserialized back to the original value.

reproducible test case:

    @Test
    void shouldSerializeAndDeserializeSse() {
        // given
        String originalData = "\n\n";
        String expectedSerialized =
                "id:1\n" +
                        "event:message\n" +
                        "data:\n" +
                        "data:\n" +
                        "data:\n\n";

        Flux<ServerSentEvent<String>> events = Flux.just(
                ServerSentEvent.builder(originalData)
                        .id("1")
                        .event("message")
                        .build()
        );

        // when – serialize
        MockServerHttpResponse response = new MockServerHttpResponse();
        ServerSentEventHttpMessageWriter writer = new ServerSentEventHttpMessageWriter();
        ResolvableType eventType = ResolvableType.forClassWithGenerics(ServerSentEvent.class, String.class);
        writer.write(events, eventType, MediaType.TEXT_EVENT_STREAM, response, null).block();

        String actualSerialized = response.getBodyAsString().block();

        // then – check serialization
        assertThat(actualSerialized).isEqualTo(expectedSerialized); // passes

        // when – deserialize back
        ServerSentEventHttpMessageReader reader = new ServerSentEventHttpMessageReader();
        List<ServerSentEvent<String>> deserialized = reader
                .read(eventType, new MockInputMessage(actualSerialized), Collections.emptyMap())
                .cast((Class<ServerSentEvent<String>>)(Class<?>)ServerSentEvent.class)
                .collectList()
                .block();

        // then – check deserialization
        assertThat(deserialized).hasSize(1);
        assertThat(deserialized.get(0).data()).isEqualTo(originalData); // fails
    }

Observed behavior:
Serialization produces the expected output.
After deserialization, data() is null instead of the original value "\n\n".

Expected behavior:
Round-trip serialization and deserialization should be consistent.

Metadata

Metadata

Assignees

Labels

in: webIssues in web modules (web, webmvc, webflux, websocket)type: enhancementA general enhancement

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions