diff --git a/buffer/src/main/java/io/netty/buffer/ByteBufUtil.java b/buffer/src/main/java/io/netty/buffer/ByteBufUtil.java index 8ce61109e9..00d6640f50 100644 --- a/buffer/src/main/java/io/netty/buffer/ByteBufUtil.java +++ b/buffer/src/main/java/io/netty/buffer/ByteBufUtil.java @@ -304,24 +304,36 @@ public final class ByteBufUtil { return -1; } - static ByteBuffer encodeString(CharBuffer src, Charset charset) { + /** + * Encode the given {@link CharBuffer} using the given {@link Charset} into a new {@link ByteBuf} which + * is allocated via the {@link ByteBufAllocator}. + */ + public static ByteBuf encodeString(ByteBufAllocator alloc, CharBuffer src, Charset charset) { final CharsetEncoder encoder = CharsetUtil.getEncoder(charset); - final ByteBuffer dst = ByteBuffer.allocate( - (int) ((double) src.remaining() * encoder.maxBytesPerChar())); + int length = (int) ((double) src.remaining() * encoder.maxBytesPerChar()); + boolean release = true; + final ByteBuf dst = alloc.buffer(length); try { - CoderResult cr = encoder.encode(src, dst, true); + final ByteBuffer dstBuf = dst.internalNioBuffer(0, length); + final int pos = dstBuf.position(); + CoderResult cr = encoder.encode(src, dstBuf, true); if (!cr.isUnderflow()) { cr.throwException(); } - cr = encoder.flush(dst); + cr = encoder.flush(dstBuf); if (!cr.isUnderflow()) { cr.throwException(); } + dst.writerIndex(dst.writerIndex() + (dstBuf.position() - pos)); + release = false; + return dst; } catch (CharacterCodingException x) { throw new IllegalStateException(x); + } finally { + if (release) { + dst.release(); + } } - dst.flip(); - return dst; } static String decodeString(ByteBuffer src, Charset charset) { diff --git a/buffer/src/main/java/io/netty/buffer/Unpooled.java b/buffer/src/main/java/io/netty/buffer/Unpooled.java index 2a16be9149..6e1654e41c 100644 --- a/buffer/src/main/java/io/netty/buffer/Unpooled.java +++ b/buffer/src/main/java/io/netty/buffer/Unpooled.java @@ -647,10 +647,7 @@ public final class Unpooled { } private static ByteBuf copiedBuffer(CharBuffer buffer, Charset charset) { - ByteBuffer dst = ByteBufUtil.encodeString(buffer, charset); - ByteBuf result = wrappedBuffer(dst.array()); - result.writerIndex(dst.remaining()); - return result; + return ByteBufUtil.encodeString(ALLOC, buffer, charset); } /** diff --git a/codec/src/main/java/io/netty/handler/codec/string/StringEncoder.java b/codec/src/main/java/io/netty/handler/codec/string/StringEncoder.java index 4d49ba0f90..9177faece1 100644 --- a/codec/src/main/java/io/netty/handler/codec/string/StringEncoder.java +++ b/codec/src/main/java/io/netty/handler/codec/string/StringEncoder.java @@ -16,13 +16,14 @@ package io.netty.handler.codec.string; import io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; +import io.netty.buffer.ByteBufUtil; import io.netty.channel.ChannelHandler.Sharable; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelPipeline; import io.netty.handler.codec.LineBasedFrameDecoder; import io.netty.handler.codec.MessageToMessageEncoder; +import java.nio.CharBuffer; import java.nio.charset.Charset; import java.util.List; @@ -76,6 +77,6 @@ public class StringEncoder extends MessageToMessageEncoder { return; } - out.add(Unpooled.copiedBuffer(msg, charset)); + out.add(ByteBufUtil.encodeString(ctx.alloc(), CharBuffer.wrap(msg), charset)); } } diff --git a/codec/src/test/java/io/netty/handler/codec/string/StringEncoderTest.java b/codec/src/test/java/io/netty/handler/codec/string/StringEncoderTest.java new file mode 100644 index 0000000000..8c95bff302 --- /dev/null +++ b/codec/src/test/java/io/netty/handler/codec/string/StringEncoderTest.java @@ -0,0 +1,38 @@ +/* + * Copyright 2014 The Netty Project + * + * The Netty Project licenses this file to you 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 io.netty.handler.codec.string; + +import io.netty.buffer.ByteBuf; +import io.netty.channel.embedded.EmbeddedChannel; +import io.netty.util.CharsetUtil; +import org.junit.Assert; +import org.junit.Test; + +public class StringEncoderTest { + + @Test + public void testEncode() { + String msg = "Test"; + EmbeddedChannel channel = new EmbeddedChannel(new StringEncoder()); + Assert.assertTrue(channel.writeOutbound(msg)); + Assert.assertTrue(channel.finish()); + ByteBuf buf = (ByteBuf) channel.readOutbound(); + byte[] data = new byte[buf.readableBytes()]; + buf.readBytes(data); + Assert.assertArrayEquals(msg.getBytes(CharsetUtil.UTF_8), data); + Assert.assertNull(channel.readOutbound()); + } +}