diff --git a/spring-test/src/main/java/org/springframework/mock/http/server/reactive/MockServerHttpResponse.java b/spring-test/src/main/java/org/springframework/mock/http/server/reactive/MockServerHttpResponse.java index 6ab8116d6c..32e00b35b3 100644 --- a/spring-test/src/main/java/org/springframework/mock/http/server/reactive/MockServerHttpResponse.java +++ b/spring-test/src/main/java/org/springframework/mock/http/server/reactive/MockServerHttpResponse.java @@ -16,6 +16,8 @@ package org.springframework.mock.http.server.reactive; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; import java.util.function.Supplier; import org.reactivestreams.Publisher; @@ -24,11 +26,14 @@ import reactor.core.publisher.Mono; import org.springframework.core.io.buffer.DataBuffer; import org.springframework.core.io.buffer.DataBufferFactory; +import org.springframework.core.io.buffer.DataBufferUtils; import org.springframework.core.io.buffer.DefaultDataBufferFactory; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; import org.springframework.http.ResponseCookie; import org.springframework.http.server.reactive.ServerHttpResponse; +import org.springframework.util.Assert; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; @@ -106,4 +111,42 @@ public class MockServerHttpResponse implements ServerHttpResponse { return this.bufferFactory; } + /** + * Return the body of the response aggregated and converted to a String + * using the charset of the Content-Type response or otherwise defaulting + * to "UTF-8". + */ + public Mono getBodyAsString() { + Charset charset = getCharset(); + Charset charsetToUse = (charset != null ? charset : StandardCharsets.UTF_8); + return Flux.from(this.body) + .reduce(this.bufferFactory.allocateBuffer(), (previous, current) -> { + previous.write(current); + DataBufferUtils.release(current); + return previous; + }) + .map(buffer -> dumpString(buffer, charsetToUse)); + } + + private static String dumpString(DataBuffer buffer, Charset charset) { + Assert.notNull(charset, "'charset' must not be null"); + byte[] bytes = dumpBytes(buffer); + return new String(bytes, charset); + } + + private static byte[] dumpBytes(DataBuffer buffer) { + Assert.notNull(buffer, "'buffer' must not be null"); + byte[] bytes = new byte[buffer.readableByteCount()]; + buffer.read(bytes); + return bytes; + } + + private Charset getCharset() { + MediaType contentType = getHeaders().getContentType(); + if (contentType != null) { + return contentType.getCharset(); + } + return null; + } + } diff --git a/spring-web/src/test/java/org/springframework/http/codec/EncoderHttpMessageWriterTest.java b/spring-web/src/test/java/org/springframework/http/codec/EncoderHttpMessageWriterTest.java index c79325313c..97d518e03a 100644 --- a/spring-web/src/test/java/org/springframework/http/codec/EncoderHttpMessageWriterTest.java +++ b/spring-web/src/test/java/org/springframework/http/codec/EncoderHttpMessageWriterTest.java @@ -1,5 +1,21 @@ +/* + * Copyright 2002-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.springframework.http.codec; +import static java.nio.charset.StandardCharsets.UTF_8; import static org.junit.Assert.*; import static org.hamcrest.Matchers.*; @@ -7,11 +23,13 @@ import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; import java.util.Collections; +import org.jetbrains.annotations.NotNull; import org.junit.Test; import reactor.core.publisher.Mono; import org.springframework.core.ResolvableType; import org.springframework.core.codec.ByteBufferEncoder; +import org.springframework.core.codec.Encoder; import org.springframework.http.MediaType; import org.springframework.mock.http.server.reactive.test.MockServerHttpResponse; import org.springframework.tests.TestSubscriber; @@ -21,35 +39,42 @@ import org.springframework.util.MimeTypeUtils; * Unit tests for {@link EncoderHttpMessageWriter}. * * @author Marcin Kamionowski + * @author Rossen Stoyanchev */ public class EncoderHttpMessageWriterTest { - private EncoderHttpMessageWriter writer = new EncoderHttpMessageWriter<>(new ByteBufferEncoder()); - private MockServerHttpResponse response = new MockServerHttpResponse(); + @Test public void writableMediaTypes() throws Exception { + EncoderHttpMessageWriter writer = createWriter(new ByteBufferEncoder()); assertThat(writer.getWritableMediaTypes(), containsInAnyOrder(MimeTypeUtils.ALL)); } @Test public void supportedMediaTypes() throws Exception { - assertTrue(writer.canWrite(ResolvableType.forClass(ByteBuffer.class), - MediaType.ALL)); - assertTrue(writer.canWrite(ResolvableType.forClass(ByteBuffer.class), - MediaType.TEXT_PLAIN)); + EncoderHttpMessageWriter writer = createWriter(new ByteBufferEncoder()); + assertTrue(writer.canWrite(ResolvableType.forClass(ByteBuffer.class), MediaType.ALL)); + assertTrue(writer.canWrite(ResolvableType.forClass(ByteBuffer.class), MediaType.TEXT_PLAIN)); } @Test public void encodeByteBuffer(){ String payload = "Buffer payload"; - Mono source = Mono.just(ByteBuffer.wrap(payload.getBytes(StandardCharsets.UTF_8))); + Mono source = Mono.just(ByteBuffer.wrap(payload.getBytes(UTF_8))); + EncoderHttpMessageWriter writer = createWriter(new ByteBufferEncoder()); writer.write(source, ResolvableType.forClass(ByteBuffer.class), - MediaType.APPLICATION_OCTET_STREAM, response, Collections.emptyMap()); + MediaType.APPLICATION_OCTET_STREAM, this.response, Collections.emptyMap()); assertThat(this.response.getHeaders().getContentType(), is(MediaType.APPLICATION_OCTET_STREAM)); - TestSubscriber.subscribe(response.getBodyAsString()).assertComplete().assertValues(payload); + TestSubscriber.subscribe(this.response.getBodyAsString()).assertComplete().assertValues(payload); } + + @NotNull + private EncoderHttpMessageWriter createWriter(Encoder encoder) { + return new EncoderHttpMessageWriter<>(encoder); + } + } \ No newline at end of file diff --git a/spring-web/src/test/java/org/springframework/http/codec/ResourceHttpMessageWriterTests.java b/spring-web/src/test/java/org/springframework/http/codec/ResourceHttpMessageWriterTests.java index eebb170feb..7c0b1eaf4f 100644 --- a/spring-web/src/test/java/org/springframework/http/codec/ResourceHttpMessageWriterTests.java +++ b/spring-web/src/test/java/org/springframework/http/codec/ResourceHttpMessageWriterTests.java @@ -76,7 +76,7 @@ public class ResourceHttpMessageWriterTests { assertThat(this.response.getHeaders().getContentLength(), is(39L)); assertThat(this.response.getHeaders().getFirst(HttpHeaders.ACCEPT_RANGES), is("bytes")); - Mono result = response.getBodyAsString(); + Mono result = this.response.getBodyAsString(); TestSubscriber.subscribe(result).assertComplete().assertValues("Spring Framework test resource content."); } @@ -92,7 +92,7 @@ public class ResourceHttpMessageWriterTests { assertThat(this.response.getHeaders().getFirst(HttpHeaders.ACCEPT_RANGES), is("bytes")); assertThat(this.response.getHeaders().getContentLength(), is(6L)); - Mono result = response.getBodyAsString(); + Mono result = this.response.getBodyAsString(); TestSubscriber.subscribe(result).assertComplete().assertValues("Spring"); } diff --git a/spring-web/src/test/java/org/springframework/mock/http/server/reactive/test/MockServerHttpResponse.java b/spring-web/src/test/java/org/springframework/mock/http/server/reactive/test/MockServerHttpResponse.java index dc5fc3523b..d95ffc7434 100644 --- a/spring-web/src/test/java/org/springframework/mock/http/server/reactive/test/MockServerHttpResponse.java +++ b/spring-web/src/test/java/org/springframework/mock/http/server/reactive/test/MockServerHttpResponse.java @@ -16,6 +16,7 @@ package org.springframework.mock.http.server.reactive.test; +import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.util.function.Supplier; @@ -30,6 +31,7 @@ import org.springframework.core.io.buffer.DefaultDataBufferFactory; import org.springframework.core.io.buffer.support.DataBufferTestUtils; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; import org.springframework.http.ResponseCookie; import org.springframework.http.server.reactive.ServerHttpResponse; import org.springframework.util.LinkedMultiValueMap; @@ -109,16 +111,29 @@ public class MockServerHttpResponse implements ServerHttpResponse { return this.bufferFactory; } + /** + * Return the body of the response aggregated and converted to a String + * using the charset of the Content-Type response or otherwise defaulting + * to "UTF-8". + */ public Mono getBodyAsString() { - - return Flux.from(body) - .reduce(bufferFactory.allocateBuffer(), (previous, current) -> { + Charset charset = getCharset(); + Charset charsetToUse = (charset != null ? charset : StandardCharsets.UTF_8); + return Flux.from(this.body) + .reduce(this.bufferFactory.allocateBuffer(), (previous, current) -> { previous.write(current); DataBufferUtils.release(current); return previous; }) - .map(buffer -> DataBufferTestUtils.dumpString(buffer, StandardCharsets.UTF_8)); + .map(buffer -> DataBufferTestUtils.dumpString(buffer, charsetToUse)); } + private Charset getCharset() { + MediaType contentType = getHeaders().getContentType(); + if (contentType != null) { + return contentType.getCharset(); + } + return null; + } }