TFrameCodec extends ByteToMessageCodec<TFrame> { @Override protected void decode(ChannelHandlerContext ctx, ByteBuf msg, List<Object> out) throws Exception { msg.retain(); boolean release = true; try { out.add(decode(msg)); release = false; } finally { if (release) { msg.release(); } } }  static ByteBuf encode(ByteBufAllocator allocator, TFrame frame); static TFrame decode(ByteBuf buffer);  }
@Test public void decodeWithErrorDoesntRetainExtraCopy() throws Exception { ByteBuf input = Unpooled.buffer(TFrame.FRAME_SIZE_LENGTH); ChannelHandlerContext ctx = mock(ChannelHandlerContext.class); assertEquals(1, input.refCnt()); try { new TFrameCodec().decode(ctx, input, new ArrayList<Object>()); fail(); } catch (IndexOutOfBoundsException e) { assertTrue(e .getMessage() .contains( "readerIndex(0) + length(2) exceeds writerIndex(0): ")); } assertEquals(1, input.refCnt()); }
@Test public void decodeWithoutErrorRetainsExtraCopy() throws Exception { ByteBuf input = Unpooled.buffer(2 * TFrame.FRAME_HEADER_LENGTH); byte[] payload = "hello".getBytes(Charsets.US_ASCII); input.writeShort((payload.length + TFrame.FRAME_HEADER_LENGTH)); input.writeByte(1); input.writeByte(1); input.writeInt(25); input.writeBytes(new byte[]{0,0,0,0,0,0,0,0}); input.writeBytes(payload); ChannelHandlerContext ctx = mock(ChannelHandlerContext.class); assertEquals(1, input.refCnt()); ArrayList<Object> out = new ArrayList<>(); new TFrameCodec().decode(ctx, input, out); assertEquals(1, out.size()); assertEquals("hello", ((TFrame)out.get(0)).payload.toString(Charsets.US_ASCII)); assertEquals(2, input.refCnt()); }