Skip to content

Commit 9332b3f

Browse files
committed
Have ReactiveTypeHandler consider +x-ndjson suffix as streaming
This commit adds `application/*+x-ndjson`, a wildcard media type which covers all types that can be parsed as nd-json, to the list of media types the ReactiveTypeHandler considers for a streaming response in WebMVC. As a result, a request which for example `Accept` the `application/vnd.myapp.v1+x-ndjson` media type will generate a response with the same `Content-Type`, with newline-delimited json objects being streamed in the response body. Closes gh-26817
1 parent 5f13b2b commit 9332b3f

File tree

2 files changed

+29
-2
lines changed

2 files changed

+29
-2
lines changed

spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ReactiveTypeHandler.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,8 @@ class ReactiveTypeHandler {
8080

8181
@SuppressWarnings("deprecation")
8282
private static final List<MediaType> JSON_STREAMING_MEDIA_TYPES =
83-
Arrays.asList(MediaType.APPLICATION_NDJSON, MediaType.APPLICATION_STREAM_JSON);
83+
Arrays.asList(MediaType.APPLICATION_NDJSON, MediaType.APPLICATION_STREAM_JSON,
84+
MediaType.valueOf("application/*+x-ndjson"));
8485

8586
private static final boolean isContextPropagationPresent = ClassUtils.isPresent(
8687
"io.micrometer.context.ContextSnapshot", ReactiveTypeHandler.class.getClassLoader());
@@ -165,7 +166,7 @@ public ResponseBodyEmitter handleValue(Object returnValue, MethodParameter retur
165166
for (MediaType streamingType : JSON_STREAMING_MEDIA_TYPES) {
166167
if (streamingType.includes(type)) {
167168
logExecutorWarning(returnType);
168-
ResponseBodyEmitter emitter = getEmitter(streamingType);
169+
ResponseBodyEmitter emitter = getEmitter(type);
169170
new JsonEmitterSubscriber(emitter, this.taskExecutor).connect(adapter, returnValue);
170171
return emitter;
171172
}

spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ReactiveTypeHandlerTests.java

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,32 @@ public void writeStreamJson() throws Exception {
255255
assertThat(emitterHandler.getValues()).isEqualTo(Arrays.asList(bar1, "\n", bar2, "\n"));
256256
}
257257

258+
@Test
259+
public void writeStreamJsonWithVendorSubtype() throws Exception {
260+
this.servletRequest.addHeader("Accept", "application/vnd.myapp.v1+x-ndjson");
261+
262+
Sinks.Many<Bar> sink = Sinks.many().unicast().onBackpressureBuffer();
263+
ResponseBodyEmitter emitter = handleValue(sink.asFlux(), Flux.class, forClass(Bar.class));
264+
265+
assertThat(emitter).as("emitter").isNotNull();
266+
267+
EmitterHandler emitterHandler = new EmitterHandler();
268+
emitter.initialize(emitterHandler);
269+
270+
ServletServerHttpResponse message = new ServletServerHttpResponse(this.servletResponse);
271+
emitter.extendResponse(message);
272+
273+
Bar bar1 = new Bar("foo");
274+
Bar bar2 = new Bar("bar");
275+
276+
sink.tryEmitNext(bar1);
277+
sink.tryEmitNext(bar2);
278+
sink.tryEmitComplete();
279+
280+
assertThat(message.getHeaders().getContentType().toString()).isEqualTo("application/vnd.myapp.v1+x-ndjson");
281+
assertThat(emitterHandler.getValues()).isEqualTo(Arrays.asList(bar1, "\n", bar2, "\n"));
282+
}
283+
258284
@Test
259285
public void writeText() throws Exception {
260286

0 commit comments

Comments
 (0)