Class ByteToMessageDecoder

java.lang.Object
io.netty.channel.ChannelHandlerAdapter
io.netty.channel.ChannelInboundHandlerAdapter
io.netty.handler.codec.ByteToMessageDecoder
All Implemented Interfaces:
io.netty.channel.ChannelHandler, io.netty.channel.ChannelInboundHandler
Direct Known Subclasses:
BrotliDecoder, Bzip2Decoder, DelimiterBasedFrameDecoder, FastLzFrameDecoder, FixedLengthFrameDecoder, JsonObjectDecoder, LengthFieldBasedFrameDecoder, LineBasedFrameDecoder, Lz4FrameDecoder, LzfDecoder, ProtobufVarint32FrameDecoder, ReplayingDecoder, SnappyFrameDecoder, XmlFrameDecoder, ZlibDecoder

public abstract class ByteToMessageDecoder extends io.netty.channel.ChannelInboundHandlerAdapter
ChannelInboundHandlerAdapter which decodes bytes in a stream-like fashion from one ByteBuf to an other Message type. For example here is an implementation which reads all readable bytes from the input ByteBuf and create a new ByteBuf.
     public class SquareDecoder extends ByteToMessageDecoder {
         @Override
         public void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out)
                 throws Exception {
             out.add(in.readBytes(in.readableBytes()));
         }
     }
 

Frame detection

Generally frame detection should be handled earlier in the pipeline by adding a DelimiterBasedFrameDecoder, FixedLengthFrameDecoder, LengthFieldBasedFrameDecoder, or LineBasedFrameDecoder.

If a custom frame decoder is required, then one needs to be careful when implementing one with ByteToMessageDecoder. Ensure there are enough bytes in the buffer for a complete frame by checking ByteBuf.readableBytes(). If there are not enough bytes for a complete frame, return without modifying the reader index to allow more bytes to arrive.

To check for complete frames without modifying the reader index, use methods like ByteBuf.getInt(int). One MUST use the reader index when using methods like ByteBuf.getInt(int). For example calling in.getInt(0) is assuming the frame starts at the beginning of the buffer, which is not always the case. Use in.getInt(in.readerIndex()) instead.

Pitfalls

Be aware that sub-classes of ByteToMessageDecoder MUST NOT annotated with

invalid @link
{@link @Sharable
}.

Some methods such as ByteBuf.readBytes(int) will cause a memory leak if the returned buffer is not released or added to the out List. Use derived buffers like ByteBuf.readSlice(int) to avoid leaking memory.

  • Field Details

    • MERGE_CUMULATOR

      public static final ByteToMessageDecoder.Cumulator MERGE_CUMULATOR
      Cumulate ByteBufs by merge them into one ByteBuf's, using memory copies.
    • COMPOSITE_CUMULATOR

      public static final ByteToMessageDecoder.Cumulator COMPOSITE_CUMULATOR
      Cumulate ByteBufs by add them to a CompositeByteBuf and so do no memory copy whenever possible. Be aware that CompositeByteBuf use a more complex indexing implementation so depending on your use-case and the decoder implementation this may be slower than just use the MERGE_CUMULATOR.
  • Constructor Details

    • ByteToMessageDecoder

      protected ByteToMessageDecoder()
  • Method Details

    • setSingleDecode

      public void setSingleDecode(boolean singleDecode)
      If set then only one message is decoded on each channelRead(ChannelHandlerContext, Object) call. This may be useful if you need to do some protocol upgrade and want to make sure nothing is mixed up. Default is false as this has performance impacts.
    • isSingleDecode

      public boolean isSingleDecode()
      If true then only one message is decoded on each channelRead(ChannelHandlerContext, Object) call. Default is false as this has performance impacts.
    • setCumulator

      public void setCumulator(ByteToMessageDecoder.Cumulator cumulator)
      Set the ByteToMessageDecoder.Cumulator to use for cumulate the received ByteBufs.
    • setDiscardAfterReads

      public void setDiscardAfterReads(int discardAfterReads)
      Set the number of reads after which ByteBuf.discardSomeReadBytes() are called and so free up memory. The default is 16.
    • actualReadableBytes

      protected int actualReadableBytes()
      Returns the actual number of readable bytes in the internal cumulative buffer of this decoder. You usually do not need to rely on this value to write a decoder. Use it only when you must use it at your own risk. This method is a shortcut to internalBuffer().readableBytes().
    • internalBuffer

      protected io.netty.buffer.ByteBuf internalBuffer()
      Returns the internal cumulative buffer of this decoder. You usually do not need to access the internal buffer directly to write a decoder. Use it only when you must use it at your own risk.
    • handlerRemoved

      public final void handlerRemoved(io.netty.channel.ChannelHandlerContext ctx) throws Exception
      Specified by:
      handlerRemoved in interface io.netty.channel.ChannelHandler
      Overrides:
      handlerRemoved in class io.netty.channel.ChannelHandlerAdapter
      Throws:
      Exception
    • handlerRemoved0

      protected void handlerRemoved0(io.netty.channel.ChannelHandlerContext ctx) throws Exception
      Gets called after the ByteToMessageDecoder was removed from the actual context and it doesn't handle events anymore.
      Throws:
      Exception
    • channelRead

      public void channelRead(io.netty.channel.ChannelHandlerContext ctx, Object msg) throws Exception
      Specified by:
      channelRead in interface io.netty.channel.ChannelInboundHandler
      Overrides:
      channelRead in class io.netty.channel.ChannelInboundHandlerAdapter
      Throws:
      Exception
    • channelReadComplete

      public void channelReadComplete(io.netty.channel.ChannelHandlerContext ctx) throws Exception
      Specified by:
      channelReadComplete in interface io.netty.channel.ChannelInboundHandler
      Overrides:
      channelReadComplete in class io.netty.channel.ChannelInboundHandlerAdapter
      Throws:
      Exception
    • discardSomeReadBytes

      protected final void discardSomeReadBytes()
    • channelInactive

      public void channelInactive(io.netty.channel.ChannelHandlerContext ctx) throws Exception
      Specified by:
      channelInactive in interface io.netty.channel.ChannelInboundHandler
      Overrides:
      channelInactive in class io.netty.channel.ChannelInboundHandlerAdapter
      Throws:
      Exception
    • userEventTriggered

      public void userEventTriggered(io.netty.channel.ChannelHandlerContext ctx, Object evt) throws Exception
      Specified by:
      userEventTriggered in interface io.netty.channel.ChannelInboundHandler
      Overrides:
      userEventTriggered in class io.netty.channel.ChannelInboundHandlerAdapter
      Throws:
      Exception
    • callDecode

      protected void callDecode(io.netty.channel.ChannelHandlerContext ctx, io.netty.buffer.ByteBuf in, List<Object> out)
      Called once data should be decoded from the given ByteBuf. This method will call decode(ChannelHandlerContext, ByteBuf, List) as long as decoding should take place.
      Parameters:
      ctx - the ChannelHandlerContext which this ByteToMessageDecoder belongs to
      in - the ByteBuf from which to read data
      out - the List to which decoded messages should be added
    • decode

      protected abstract void decode(io.netty.channel.ChannelHandlerContext ctx, io.netty.buffer.ByteBuf in, List<Object> out) throws Exception
      Decode the from one ByteBuf to an other. This method will be called till either the input ByteBuf has nothing to read when return from this method or till nothing was read from the input ByteBuf.
      Parameters:
      ctx - the ChannelHandlerContext which this ByteToMessageDecoder belongs to
      in - the ByteBuf from which to read data
      out - the List to which decoded messages should be added
      Throws:
      Exception - is thrown if an error occurs
    • decodeLast

      protected void decodeLast(io.netty.channel.ChannelHandlerContext ctx, io.netty.buffer.ByteBuf in, List<Object> out) throws Exception
      Is called one last time when the ChannelHandlerContext goes in-active. Which means the channelInactive(ChannelHandlerContext) was triggered. By default, this will just call decode(ChannelHandlerContext, ByteBuf, List) but sub-classes may override this for some special cleanup operation.
      Throws:
      Exception