views:

807

answers:

4

I have a few classes such that:

public class XMLStatusMessage extends XMLMessage
{}
public abstract class XMLMessage implements IMessage
{}

public interface IMessageListener
{
    public void onMessage( IMessage message );
}

public interface XMLMessageListener <T extends XMLMessage> extends 
    IMessageListener
{
    public void onMessage( T message ); 
}

public interface XMLStatusMessageListener extends 
    XMLMessageListener <XMLStatusMessage>
{
    @Override
    public void onMessage( XMLStatusMessage message );
}

and

public class AStatusHandler implements XMLStatusMessageListener
{
    //...
    @Override
    public void onMessage( XMLStatusMessage message )
    {
     //...
    }
}

My problem is that AStatusHandler won't compile because I'm not also implementing public void onMessage(IMessage). I don't see why I should have to implement onMessage(IMessage) also as it already implements onMessage(XMLStatusMessage) and XMLStatusMessage is an IMessage. Is there a simple solution to this problem?

A: 

I've been in these situations before, but there isn't really a beautiful solution to this problem.

In your case, IMessageListener defines onMessage to receive an IMessage.

Your XMLMessageListener which extends it defines onMessage to receive at least an XMLMessage.

Even if you ignored the generics, Java does not allow you to change a parameter type in an overriding version of the method. So the two methods are considered an overload, and your code would not compile because you do not have a definition for the version that receives an IMessage.

Uri
A: 

An XMLStatusMessage is an IMessage, but not the reverse. If there was another subclass of IMessage, say SMTPStatusMessage, then:

  1. onMessage(IMessage) could be handed an SMTPStatusMessage legitimately, but
  2. onMessage(XMLStatusMessage) could not.

If you don't expect to have anything other than an XMLStatusMessage sent to AStatusHandler, then you can have onMessage(IMessage) cast the IMessage to an XMLStatusMessage and call onMessage(XMLStatusMessage), but that's not a great longterm strategy.

EDIT: Really, the question is why the XMLMessageListener is a subclass of IMessageListener at all, since presumably the classes calling onMessage(XMLStatusMessage) are never going to call onMessage(IMessage)?

Richard Campbell
+1  A: 

You're claiming (by implementing IMessageListener) that you can call onMessage with any IMessage. What would you expect to happen if you called:

new XMLMessageListener().onMessage(new SomeOtherMessage());

? If you think that shouldn't be allowed, you shouldn't be implementing IMessageListener.

Jon Skeet
+2  A: 

As the other answers point out, you will only be able handle XMLStatusMessage messages in AStatusHandler, but my guess is that this is what you want? Redeclare your interfaces as follows and I believe you will get what you want;

public interface IMessageListener<T extends IMessage> {

    public void onMessage(T message);
}

public interface XMLMessageListener<T extends XMLMessage> extends IMessageListener<T> {
}

public interface XMLStatusMessageListener extends XMLMessageListener<XMLStatusMessage> {
}

Then you can create your message listener as follows;

public class AStatusHandler implements XMLStatusMessageListener {

    @Override
    public void onMessage(final XMLStatusMessage message) {

        // TODO Auto-generated method stub

    }

}

Hope this is what you want, and that it helps.

Regards Bent

Bent André Solheim
This makes sense and works! Thanks!