diff --git a/spring-core/src/main/java/org/springframework/core/io/buffer/DataBuffer.java b/spring-core/src/main/java/org/springframework/core/io/buffer/DataBuffer.java index 86d10c0f50..ca7ad0f3ea 100644 --- a/spring-core/src/main/java/org/springframework/core/io/buffer/DataBuffer.java +++ b/spring-core/src/main/java/org/springframework/core/io/buffer/DataBuffer.java @@ -355,4 +355,28 @@ public interface DataBuffer { */ OutputStream asOutputStream(); + /** + * Return this buffer's data a String using the specified charset. Default implementation + * delegates to {@code toString(readPosition(), readableByteCount(), charset)}. + * + * @param charset the character set to use + * @return a string representation of all this buffers data + * @since 5.2 + */ + default String toString(Charset charset) { + Assert.notNull(charset, "Charset must not be null"); + return toString(readPosition(), readableByteCount(), charset); + } + + /** + * Return a part of this buffer's data as a String using the specified charset. + * + * @param index the index at which to start the string + * @param length the number of bytes to use for the string + * @param charset the charset to use + * @return a string representation of a part of this buffers data + * @since 5.2 + */ + String toString(int index, int length, Charset charset); + } diff --git a/spring-core/src/main/java/org/springframework/core/io/buffer/DefaultDataBuffer.java b/spring-core/src/main/java/org/springframework/core/io/buffer/DefaultDataBuffer.java index a7a7f9b891..fd2fcdf288 100644 --- a/spring-core/src/main/java/org/springframework/core/io/buffer/DefaultDataBuffer.java +++ b/spring-core/src/main/java/org/springframework/core/io/buffer/DefaultDataBuffer.java @@ -21,6 +21,7 @@ import java.io.InputStream; import java.io.OutputStream; import java.nio.Buffer; import java.nio.ByteBuffer; +import java.nio.charset.Charset; import java.util.Arrays; import java.util.function.IntPredicate; @@ -381,6 +382,28 @@ public class DefaultDataBuffer implements DataBuffer { } + @Override + public String toString(int index, int length, Charset charset) { + checkIndex(index, length); + Assert.notNull(charset, "Charset must not be null"); + + byte[] bytes; + int offset; + + if (this.byteBuffer.hasArray()) { + bytes = this.byteBuffer.array(); + offset = this.byteBuffer.arrayOffset() + index; + } + else { + bytes = new byte[length]; + offset = 0; + ByteBuffer duplicate = this.byteBuffer.duplicate(); + duplicate.clear().position(index).limit(index + length); + duplicate.get(bytes, 0, length); + } + return new String(bytes, offset, length, charset); + } + /** * Calculate the capacity of the buffer. * @see io.netty.buffer.AbstractByteBufAllocator#calculateNewCapacity(int, int) diff --git a/spring-core/src/main/java/org/springframework/core/io/buffer/NettyDataBuffer.java b/spring-core/src/main/java/org/springframework/core/io/buffer/NettyDataBuffer.java index 9b428301fe..7b37f8bd51 100644 --- a/spring-core/src/main/java/org/springframework/core/io/buffer/NettyDataBuffer.java +++ b/spring-core/src/main/java/org/springframework/core/io/buffer/NettyDataBuffer.java @@ -293,6 +293,18 @@ public class NettyDataBuffer implements PooledDataBuffer { return new ByteBufOutputStream(this.byteBuf); } + @Override + public String toString(Charset charset) { + Assert.notNull(charset, "Charset must not be null"); + return this.byteBuf.toString(charset); + } + + @Override + public String toString(int index, int length, Charset charset) { + Assert.notNull(charset, "Charset must not be null"); + return this.byteBuf.toString(index, length, charset); + } + @Override public boolean isAllocated() { return this.byteBuf.refCnt() > 0; diff --git a/spring-core/src/test/java/org/springframework/core/io/buffer/DataBufferTests.java b/spring-core/src/test/java/org/springframework/core/io/buffer/DataBufferTests.java index e2a3107bc9..99a72e8303 100644 --- a/spring-core/src/test/java/org/springframework/core/io/buffer/DataBufferTests.java +++ b/spring-core/src/test/java/org/springframework/core/io/buffer/DataBufferTests.java @@ -235,6 +235,44 @@ public class DataBufferTests extends AbstractDataBufferAllocatingTestCase { release(buffer); } + @Test + public void toStringNullCharset() { + DataBuffer buffer = createDataBuffer(1); + try { + assertThatIllegalArgumentException().isThrownBy(() -> + buffer.toString(null)); + } + finally { + release(buffer); + } + } + + @Test + public void toStringUtf8() { + String spring = "Spring"; + byte[] bytes = spring.getBytes(StandardCharsets.UTF_8); + DataBuffer buffer = createDataBuffer(bytes.length); + buffer.write(bytes); + + String result = buffer.toString(StandardCharsets.UTF_8); + + assertThat(result).isEqualTo(spring); + release(buffer); + } + + @Test + public void toStringSection() { + String spring = "Spring"; + byte[] bytes = spring.getBytes(StandardCharsets.UTF_8); + DataBuffer buffer = createDataBuffer(bytes.length); + buffer.write(bytes); + + String result = buffer.toString(1, 3, StandardCharsets.UTF_8); + + assertThat(result).isEqualTo("pri"); + release(buffer); + } + @Test public void inputStream() throws IOException { DataBuffer buffer = createDataBuffer(4);