Improve handling of empty response with Mono<T>

Issue: SPR-17560
This commit is contained in:
Rossen Stoyanchev 2018-11-19 16:47:51 -05:00
parent 63275ae2b7
commit abf9ce8a34
3 changed files with 28 additions and 13 deletions

View File

@ -119,7 +119,10 @@ public class EncoderHttpMessageWriter<T> implements HttpMessageWriter<T> {
if (inputStream instanceof Mono) {
HttpHeaders headers = message.getHeaders();
return Mono.from(body)
.defaultIfEmpty(message.bufferFactory().wrap(new byte[0]))
.switchIfEmpty(Mono.defer(() -> {
headers.setContentLength(0);
return message.setComplete().then(Mono.empty());
}))
.flatMap(buffer -> {
headers.setContentLength(buffer.readableByteCount());
return message.writeWith(Mono.just(buffer));

View File

@ -34,23 +34,17 @@ import reactor.test.StepVerifier;
import org.springframework.core.codec.Encoder;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DefaultDataBufferFactory;
import org.springframework.core.io.buffer.support.DataBufferTestUtils;
import org.springframework.http.MediaType;
import org.springframework.mock.http.server.reactive.test.MockServerHttpResponse;
import org.springframework.util.MimeType;
import org.springframework.util.MimeTypeUtils;
import static java.nio.charset.StandardCharsets.ISO_8859_1;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static java.nio.charset.StandardCharsets.*;
import static org.junit.Assert.*;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.when;
import static org.springframework.core.ResolvableType.forClass;
import static org.springframework.http.MediaType.TEXT_HTML;
import static org.springframework.http.MediaType.TEXT_PLAIN;
import static org.springframework.http.MediaType.TEXT_XML;
import static org.mockito.Mockito.*;
import static org.springframework.core.ResolvableType.*;
import static org.springframework.http.MediaType.*;
/**
* Unit tests for {@link EncoderHttpMessageWriter}.
@ -174,7 +168,7 @@ public class EncoderHttpMessageWriterTests {
public void emptyBodyWritten() {
HttpMessageWriter<String> writer = getWriter(MimeTypeUtils.TEXT_PLAIN);
writer.write(Mono.empty(), forClass(String.class), TEXT_PLAIN, this.response, NO_HINTS).block();
StepVerifier.create(this.response.getBody()).expectNextCount(1).verifyComplete();
StepVerifier.create(this.response.getBody()).expectComplete();
assertEquals(0, this.response.getHeaders().getContentLength());
}

View File

@ -149,6 +149,19 @@ public class RequestMappingMessageConversionIntegrationTests extends AbstractReq
assertEquals(expected, responseEntity.getBody());
}
@Test // SPR-17506
public void personResponseBodyWithEmptyMono() throws Exception {
ResponseEntity<Person> responseEntity = performGet("/person-response/mono-empty", JSON, Person.class);
assertEquals(0, responseEntity.getHeaders().getContentLength());
assertNull(responseEntity.getBody());
// As we're on the same connection, the 2nd request proves server response handling
// did complete after the 1st request..
responseEntity = performGet("/person-response/mono-empty", JSON, Person.class);
assertEquals(0, responseEntity.getHeaders().getContentLength());
assertNull(responseEntity.getBody());
}
@Test
public void personResponseBodyWithMonoDeclaredAsObject() throws Exception {
Person expected = new Person("Robert");
@ -495,6 +508,11 @@ public class RequestMappingMessageConversionIntegrationTests extends AbstractReq
return Mono.just(new Person("Robert"));
}
@GetMapping("/mono-empty")
public Mono<Person> getMonoEmpty() {
return Mono.empty();
}
@GetMapping("/mono-declared-as-object")
public Object getMonoDeclaredAsObject() {
return Mono.just(new Person("Robert"));