Multiple return types

Today I had this little problem:

I have JMS messages with common properties, and some properties set depending on message type. I want to handle all the common properties in a specific method so I don’t need to duplicate code. How can I return different types from the same method!?

Is this even possible in Java? You bet! 🙂

Let’s start with this tiny little message class:

Now, we want to be able to generate a JMS TextMessage or an ObjectMessage from this. Ideally, the methods should take a JMS Session as their parameter, to be compatible with the neat MessageCreator interface from Spring.

Let’s see:

OK, this works. Now we want to add the three common fields:

Hmm, not so nice with duplicated code! Three might work, but if you have…twelve? Not so fun!

A pre-Java 8 solution would look maybe like this:

Bleh, this is the old “use parameters as output” anti-pattern.
Old C code might do this, but we in the OOP camp are better than that, aren’t we? 🙂

So, let’s do it the Java 8 way instead!

First, let’s change that method a bit, so it returns an object instead. It needs to get the actual Message from somewhere, so we pop in a Supplier<Message> as its parameter:

Looks good! So, now we call this new method instead, and let’s ignore the subtype specific Message attributes for now:

It looks like Session::createObjectMessage and Session::createTextMessage should match the Supplier functional interface neatly 🙂

Nice! No, wait, it won’t actually compile! We get this:

The createObjectMessage and createTextMessage methods on the Session class throw JMSException, and that doesn’t fit with the functional interface Supplier<T> (which doesn’t throw anything).
The signatures have to match, not just the parameters and return types but also anything else, like throws.

Well, the solution is easy, let’s create our own functional interface instead:

OK, that problem solved. But, we still have to put the custom properties on the ObjectMessage and TextMessage.

A long time ago™ that was done using casts:

But casts are nasty and inflexible (I know, I broke my hand once!). So let’s not go there.

Now, this is where the fun starts. We need to somehow return either an ObjectMessage or a TextMessage from that method. Or, I guess, we could have two different…no, wait, forget that 🙂

The trick is to use generics. First, we need to change that functional interface a bit:

Here, the fancy part ? extends Message means “the parameter type can be MessageSupplier<Message>, MessageSupplier<ObjectMessage>, MessageSupplier<TextMessage> or something like that, but we don’t know which one right now, we only know that the type will always be a subclass of Message (or that class itself)”.

Nice, but it still returns Message! We need to somehow figure out what subclass of Message we are dealing with, and return that particular one.

Here, many novice Java developers get confused and give up, but fear not, it’s not so difficult 🙂
What we need is a bounded type parameter! This is simply a way to tell the compiler that ok, we have a name for this magic, unknown type ? extends Message, and it shall be T! So the type has a name, instead of being anonymous, which will prove useful in a little bit.

Here we go:

Not so difficult, right?

(Just remember that the T in that functional interface is not related to the T in the method. If you want that, you need to put the bounded type on the class level instead.)

The next step is where the magic happens. Yes, you might have already guessed it: we replace the return type Message with…T! And then, of course, the local variable message has to be of that type too.
But that is OK, since we already are guaranteed that our MessageSupplier<T> will in fact return an object of type T. What a coincidence 🙂

This is what it looks like:

And, happy happy joy joy, our problem is solved: we return different types of objects depending on input!
No need for casts anymore!

Here is the finished class:

Here is a simple little test class using the public methods of MyMessage to generate messages:

Getting this program to actually work is trivial and is left as an exercise for the reader.

Leave a Reply

Your email address will not be published. Required fields are marked *

Please answer this amazingly complicated math question to prove that you are not a spam bot: