Urbanleg
Urbanleg

Reputation: 6532

java polymorphism not working, what am I missing?

I have the following hierarchy in my project:

public abstract class AbstractMessage extends AbstractEntity{}
public class ParseFailedMessage extends AbstractMessage {}
public class SubParsedFailedMessage extends ParseFailedMessage {}

I have the following methods:

public AbstractMessage doHandle(AbstractMessage messageToHandle) {

   //prepareToHandle(messageToHandle);

   handle(messageToHandle);

   //finalize(messageToHandle);

   return messageToHandle;

}

@Transactional(readOnly = false)
private void handle(ParseFailedMessage message) {

   message.setHandled(false);

}

@Transactional(readOnly = false)
private void handle(AbstractMessage message) {

   message.setHandled(true);

}

For some reason when I call the doHandle(new SubParsedFailedMessage()) the function that being called from it is handle(AbstractMessage msg) and not handle(SubParsedFailedMessage msg) as emphasized text was expecting..

Can anyone say why polymorphism is not working here?

Upvotes: 1

Views: 384

Answers (2)

confusopoly
confusopoly

Reputation: 1245

Eran's explanation of the cause of the problem is correct, method overloading is evaluated at compile-time.

After thinking about it for a while I came up with a possible solution.

One solution to this problem is the Visitor design pattern:

You need an interface, call it MessageHandler that defines your handle() methods.

Put an abstract dispatch(MessageHandler handler) method on AbstractMessage and an implementation that is one line of code like so

public void dispatch(MessageHandler handler) {
    handler.handle(this)
}

in each message. This means the compiler will have the information on where to dispatch the method call at compile time and dispatch correctly. As a refactoring step say AbstractMessage implements MessageHandler. Later this can be factored out into its own class.

Side benefits: Your message handling code will be separated from your message definitions and you can replace you message handler with something different for unit tests or for different use cases.

Cons: The message handler interface needs an abstract handle()method for each message type that you want to dispatch this way.

Upvotes: 2

Eran Zimmerman Gonen
Eran Zimmerman Gonen

Reputation: 4507

doHandle is declared to receive a parameter of type AbstractMessage. This means that when your code is compiled, the code generated for the call to handle() is generated to call handle(AbstractMessage), rather than handle(ParseFailedMessage).

If you still want a function to be called according to the dynamic type of the object, you should make that function a member of SubParsedFailedMessage, and call messageToHandle.handle(). This also looks more OOP-like, and is therefore preferred.

Upvotes: 2

Related Questions