Fix handling for ResponseEntity<Flux<T>> in Spring MVC

Issue: SPR-15456
This commit is contained in:
Rossen Stoyanchev 2017-04-20 08:12:09 -04:00
parent 633544943f
commit a93698487e
2 changed files with 59 additions and 2 deletions

View File

@ -126,6 +126,7 @@ public class ResponseBodyEmitterReturnValueHandler implements HandlerMethodRetur
response.setStatus(responseEntity.getStatusCodeValue());
outputMessage.getHeaders().putAll(responseEntity.getHeaders());
returnValue = responseEntity.getBody();
returnType = returnType.nested();
if (returnValue == null) {
mavContainer.setRequestHandled(true);
outputMessage.flush();

View File

@ -22,8 +22,11 @@ import java.util.concurrent.atomic.AtomicReference;
import org.junit.Before;
import org.junit.Test;
import reactor.core.publisher.EmitterProcessor;
import reactor.core.publisher.Flux;
import org.springframework.core.MethodParameter;
import org.springframework.core.ResolvableType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
@ -95,6 +98,13 @@ public class ResponseBodyEmitterReturnValueHandlerTests {
assertTrue(this.handler.supportsReturnType(
on(TestController.class).resolveReturnType(ResponseEntity.class, ResponseBodyEmitter.class)));
assertTrue(this.handler.supportsReturnType(
on(TestController.class).resolveReturnType(Flux.class, String.class)));
assertTrue(this.handler.supportsReturnType(
on(TestController.class).resolveReturnType(forClassWithGenerics(ResponseEntity.class,
forClassWithGenerics(Flux.class, String.class)))));
}
@Test
@ -103,8 +113,8 @@ public class ResponseBodyEmitterReturnValueHandlerTests {
assertFalse(this.handler.supportsReturnType(
on(TestController.class).resolveReturnType(ResponseEntity.class, String.class)));
assertFalse(this.handler.supportsReturnType(on(TestController.class)
.resolveReturnType(forClassWithGenerics(ResponseEntity.class,
assertFalse(this.handler.supportsReturnType(
on(TestController.class).resolveReturnType(forClassWithGenerics(ResponseEntity.class,
forClassWithGenerics(AtomicReference.class, String.class)))));
assertFalse(this.handler.supportsReturnType(
@ -195,6 +205,27 @@ public class ResponseBodyEmitterReturnValueHandlerTests {
"\n", this.response.getContentAsString());
}
@Test
public void responseBodyFlux() throws Exception {
this.request.addHeader("Accept", "text/event-stream");
MethodParameter type = on(TestController.class).resolveReturnType(Flux.class, String.class);
EmitterProcessor<String> processor = EmitterProcessor.create();
this.handler.handleReturnValue(processor, type, this.mavContainer, this.webRequest);
assertTrue(this.request.isAsyncStarted());
assertEquals(200, this.response.getStatus());
assertEquals("text/event-stream;charset=UTF-8", this.response.getContentType());
processor.onNext("foo");
processor.onNext("bar");
processor.onNext("baz");
processor.onComplete();
assertEquals("data:foo\n\ndata:bar\n\ndata:baz\n\n", this.response.getContentAsString());
}
@Test
public void responseEntitySse() throws Exception {
MethodParameter type = on(TestController.class).resolveReturnType(ResponseEntity.class, SseEmitter.class);
@ -218,6 +249,27 @@ public class ResponseBodyEmitterReturnValueHandlerTests {
assertEquals(Collections.singletonList("bar"), this.response.getHeaders("foo"));
}
@Test
public void responseEntityFlux() throws Exception {
EmitterProcessor<String> processor = EmitterProcessor.create();
ResponseEntity<Flux<String>> entity = ResponseEntity.ok().body(processor);
ResolvableType bodyType = forClassWithGenerics(Flux.class, String.class);
MethodParameter type = on(TestController.class).resolveReturnType(ResponseEntity.class, bodyType);
this.handler.handleReturnValue(entity, type, this.mavContainer, this.webRequest);
assertTrue(this.request.isAsyncStarted());
assertEquals(200, this.response.getStatus());
assertEquals("text/plain", this.response.getContentType());
processor.onNext("foo");
processor.onNext("bar");
processor.onNext("baz");
processor.onComplete();
assertEquals("foobarbaz", this.response.getContentAsString());
}
@SuppressWarnings("unused")
private static class TestController {
@ -236,6 +288,10 @@ public class ResponseBodyEmitterReturnValueHandlerTests {
private ResponseEntity h7() { return null; }
private Flux<String> h8() { return null; }
private ResponseEntity<Flux<String>> h9() { return null; }
}