Skip to content

Commit

Permalink
Have ReactiveTypeHandler consider +x-ndjson suffix as streaming
Browse files Browse the repository at this point in the history
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
  • Loading branch information
simonbasle committed May 25, 2023
1 parent 5f13b2b commit 9332b3f
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,8 @@ class ReactiveTypeHandler {

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

private static final boolean isContextPropagationPresent = ClassUtils.isPresent(
"io.micrometer.context.ContextSnapshot", ReactiveTypeHandler.class.getClassLoader());
Expand Down Expand Up @@ -165,7 +166,7 @@ public ResponseBodyEmitter handleValue(Object returnValue, MethodParameter retur
for (MediaType streamingType : JSON_STREAMING_MEDIA_TYPES) {
if (streamingType.includes(type)) {
logExecutorWarning(returnType);
ResponseBodyEmitter emitter = getEmitter(streamingType);
ResponseBodyEmitter emitter = getEmitter(type);
new JsonEmitterSubscriber(emitter, this.taskExecutor).connect(adapter, returnValue);
return emitter;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,32 @@ public void writeStreamJson() throws Exception {
assertThat(emitterHandler.getValues()).isEqualTo(Arrays.asList(bar1, "\n", bar2, "\n"));
}

@Test
public void writeStreamJsonWithVendorSubtype() throws Exception {
this.servletRequest.addHeader("Accept", "application/vnd.myapp.v1+x-ndjson");

Sinks.Many<Bar> sink = Sinks.many().unicast().onBackpressureBuffer();
ResponseBodyEmitter emitter = handleValue(sink.asFlux(), Flux.class, forClass(Bar.class));

assertThat(emitter).as("emitter").isNotNull();

EmitterHandler emitterHandler = new EmitterHandler();
emitter.initialize(emitterHandler);

ServletServerHttpResponse message = new ServletServerHttpResponse(this.servletResponse);
emitter.extendResponse(message);

Bar bar1 = new Bar("foo");
Bar bar2 = new Bar("bar");

sink.tryEmitNext(bar1);
sink.tryEmitNext(bar2);
sink.tryEmitComplete();

assertThat(message.getHeaders().getContentType().toString()).isEqualTo("application/vnd.myapp.v1+x-ndjson");
assertThat(emitterHandler.getValues()).isEqualTo(Arrays.asList(bar1, "\n", bar2, "\n"));
}

@Test
public void writeText() throws Exception {

Expand Down

0 comments on commit 9332b3f

Please sign in to comment.