2

I am working with Websockets in java. I have to implement a method that takes in a generic message handler. So I wrote like this and it compiles.

public <T, M extends MessageHandler> boolean addMessageHandler(Class<T> clazz, M messageHandler) {
}

But when I try to be more specific, it throws compile time errors.

public <T, M<T> extends MessageHandler> boolean addMessageHandler(Class<T> clazz, M<T> messageHandler) {
}

Errors I get:

  1. Cannot resolve symbol 'T'
  2. '>' expected.

How can I solve this issue?

The MessageHandler interface looks like this and this is a library method so I can't alter:

public interface MessageHandler {

    interface Partial<T> extends javax.websocket.MessageHandler {
        void onMessage(T messagePart, boolean last);
    }

    interface Whole<T> extends javax.websocket.MessageHandler {
        void onMessage(T message);
    }
}
michid
  • 10,536
  • 3
  • 32
  • 59
ahrooran
  • 931
  • 1
  • 10
  • 25
  • 4
    You can't do this directly since Java does not have higher kinded types (i.e. `T`). You could try simulating higher kinded types via this trick I'm using here though: https://stackoverflow.com/questions/70681453/how-to-implement-fixed-points-of-functors-in-java – michid Sep 05 '22 at 07:53
  • 2
    The fault lies with `MessageHandler`; it needs a type parameter that ties together the two kinds of handlers. If it were generic in T and `Partial extends MessageHandler` (and same for Whole), you'd be able to do what you want. – Brian Goetz Sep 05 '22 at 17:01

1 Answers1

1

Java does not support this kind of composite generics. There is a workaround though:

  1. Define a marker interface with the generic type T:
    interface Handler<T> {}
    
  2. Define interfaces extending the provided interfaces that cannot be changed and the marker interface:
    interface PartialMessageHandler<T> extends MessageHandler.Partial<T>, 
                                               Handler<T> {}
    
    interface WholeMessageHandler<T> extends MessageHandler.Whole<T>, 
                                             Handler<T> {}
    
  3. Redefine your method like this:
    public <T, M extends Handler<T>> boolean addMessageHandler(Class<T> clazz, M messageHandler) {
        return true;
    }
    
Nikolas Charalambidis
  • 40,893
  • 16
  • 117
  • 183