Search code examples
javapolymorphismnettyinstanceofvisitor-pattern

Netty.io messageReceived override without instanceof


In netty, MessageEvent (wrapper for messages) has a method Object getMessage() to get the real carried message from the network. Reading the source I noticed they heavily use the instanceof operator to switch among methods.

However, having a wide variety of message types I would like to avoid a method like this:

public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
   if (e.getMessage() instanceof MessageType1) {
      ...
   } else if (e.getMessage() instanceof MessageType2) {
      ...
   } ... {
      ...
   } else if (e.getMessage() instanceof MessageTypeN) {
      ...
   } else {
      ctx.sendUpstream(e);
   }
}

Writing different methods taking advantage of polymorphism would be much better, like:

public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
   // MessageType implements Message
   if (e.getMessage() instanceof Message) {
      handleMessage(ctx, (Message) e.getMessage());
   } else {
      ctx.sendUpstream(e);
   }
}

void handleMessage(ChannelHandlerContext ctx, MessageType1 m) {
    ...
}

...

void handleMessage(ChannelHandlerContext ctx, MessageTypeN m) {
    ...
}

But i cannot due to downcasting limitations. Is there a clean way to do this or am I tied to instanceof cascade? I could bring the logic out the Handler using .doSomething() methods inside Message sub-types but I'd like to keep the business logic inside the netty pipeline.


Solution

  • Solved applying Visitor Pattern:

    public interface Handler {
        void handleMessage(ChannelHandlerContext ctx, MessageType1 m);
        void handleMessage(ChannelHandlerContext ctx, MessageType2 m);
        ...
        void handleMessage(ChannelHandlerContext ctx, MessageTypeN m);
    }
    

    then:

    @Sharable
    public class MessageHandler extends SimpleChannelHandler implements Handler {
       ...
       @Override
       public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
         if (e.getMessage() instanceof Message) {
            Message m = (Message) e.getMessage();
            m.handleTo(ctx, this);
        } else {
            ctx.sendUpstream(e);
        }
    }
    
    @Override
    public void handleMessage(ChannelHandlerContext ctx, MessageType1 m) {
        ...
    }
    

    and

    public interface Message {
       /*
        * Will be {
        *    handler.handleMessage(ctx, this);
        * }
        * everywhere.
        */
       void handleTo(ChannelHandlerContext ctx, Handler handler);
    }