Class ByteToMessageDecoder

java.lang.Object
io.netty.channel.ChannelHandlerAdapter
io.netty.channel.ChannelInboundHandlerAdapter
io.servicetalk.transport.netty.internal.ByteToMessageDecoder
All Implemented Interfaces:
io.netty.channel.ChannelHandler, io.netty.channel.ChannelInboundHandler

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 ChannelHandler.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.

  • Nested Class Summary

    Nested classes/interfaces inherited from interface io.netty.channel.ChannelHandler

    io.netty.channel.ChannelHandler.Sharable
  • Constructor Summary

    Constructors
    Modifier
    Constructor
    Description
    protected
    ByteToMessageDecoder(io.netty.buffer.ByteBufAllocator cumulationAllocator)
    Create a new instance.
  • Method Summary

    Modifier and Type
    Method
    Description
    void
    channelInactive(io.netty.channel.ChannelHandlerContext ctx)
     
    void
    channelRead(io.netty.channel.ChannelHandlerContext ctx, Object msg)
     
    void
    channelReadComplete(io.netty.channel.ChannelHandlerContext ctx)
     
    protected void
    Resets cumulation.
    protected abstract void
    decode(io.netty.channel.ChannelHandlerContext ctx, io.netty.buffer.ByteBuf in)
    Decode the from one ByteBuf to an other.
    protected void
    decodeLast(io.netty.channel.ChannelHandlerContext ctx, io.netty.buffer.ByteBuf in)
    Is called one last time when the ChannelHandlerContext goes in-active.
    final void
    handlerRemoved(io.netty.channel.ChannelHandlerContext ctx)
     
    protected void
    handlerRemoved0(io.netty.channel.ChannelHandlerContext ctx)
    Gets called after the ByteToMessageDecoder was removed from the actual context and it doesn't handle events anymore.
    protected io.netty.buffer.ByteBuf
    swapAndCopyCumulation(io.netty.buffer.ByteBuf cumulation, io.netty.buffer.ByteBuf in)
    Swap the existing cumulation ByteBuf for a new ByteBuf and copy in.
    void
    userEventTriggered(io.netty.channel.ChannelHandlerContext ctx, Object evt)
     

    Methods inherited from class io.netty.channel.ChannelInboundHandlerAdapter

    channelActive, channelRegistered, channelUnregistered, channelWritabilityChanged, exceptionCaught

    Methods inherited from class io.netty.channel.ChannelHandlerAdapter

    ensureNotSharable, handlerAdded, isSharable

    Methods inherited from class java.lang.Object

    clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait

    Methods inherited from interface io.netty.channel.ChannelHandler

    handlerAdded
  • Constructor Details

    • ByteToMessageDecoder

      protected ByteToMessageDecoder(io.netty.buffer.ByteBufAllocator cumulationAllocator)
      Create a new instance.
      Parameters:
      cumulationAllocator - Unpooled ByteBufAllocator used to allocate more memory, if necessary for cumulation.
      Throws:
      IllegalArgumentException - if the provided cumulationAllocator is not unpooled.
  • Method Details

    • handlerRemoved

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

      protected void handlerRemoved0(io.netty.channel.ChannelHandlerContext ctx)
      Gets called after the ByteToMessageDecoder was removed from the actual context and it doesn't handle events anymore.
      Parameters:
      ctx - the ChannelHandlerContext which this ByteToMessageDecoder belongs to
    • channelRead

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

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

      protected io.netty.buffer.ByteBuf swapAndCopyCumulation(io.netty.buffer.ByteBuf cumulation, io.netty.buffer.ByteBuf in)
      Swap the existing cumulation ByteBuf for a new ByteBuf and copy in. This method is called when a heuristic determines the amount of unused bytes is sufficiently high that a resize / defragmentation of the bytes from cumulation is beneficial.

      ByteBuf.discardReadBytes() is generally avoided in this method because it changes the underlying data structure. If others have slices of this ByteBuf their view on the data will become corrupted. This is commonly a problem when processing data asynchronously to avoid blocking the EventLoop thread.

      Parameters:
      cumulation - The ByteBuf that accumulates across socket read operations.
      in - The bytes to copy.
      Returns:
      the result of the swap and copy operation.
    • cumulationReset

      protected void cumulationReset()
      Resets cumulation.
    • channelInactive

      public void channelInactive(io.netty.channel.ChannelHandlerContext ctx)
      Specified by:
      channelInactive in interface io.netty.channel.ChannelInboundHandler
      Overrides:
      channelInactive in class io.netty.channel.ChannelInboundHandlerAdapter
    • 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
    • decode

      protected abstract void decode(io.netty.channel.ChannelHandlerContext ctx, io.netty.buffer.ByteBuf in) 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
      Throws:
      Exception - is thrown if an error occurs
    • decodeLast

      protected void decodeLast(io.netty.channel.ChannelHandlerContext ctx, io.netty.buffer.ByteBuf in) 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) but sub-classes may override this for some special cleanup operation.
      Parameters:
      ctx - the ChannelHandlerContext which this ByteToMessageDecoder belongs to
      in - the ByteBuf from which to read data
      Throws:
      Exception - is thrown if an error occurs