Unchecked warnings and type erasure with Java Generics

I am currently cleaning a whole code base from all its warnings and I kept stumbling upon a few warnings related to the use of generics. And all I can find on Google is people telling each other to use @SuppressWarnings(”unchecked”)…

For a start, I am not a big fan of annotation (I will probably post some day on that), but this is more like sidestepping the problem and acquiring bad practices for dealing with warnings.

2 different warnings

Consider the following example encountered while using Apache Log4J:

Enumeration<Appender> e = log.getAllAppenders();

This will generate the following warning: “Type safety: The expression of type Enumeration needs unchecked conversion to conform to Enumeration”

OK, fine! so let’s cast it to the proper type:

Enumeration<Appender> e = (Enumeration<Appender>)log.getAllAppenders();

Well, the result is not quite what we expected in that it’s still generating a warning: “Type safety: The cast from Enumeration to Enumeration is actually checking against the erased type Enumeration”.

Even though we are pretty sure this should never generate any ClassCastException, these warnings are just plain annoying for code quality…

More on erased types

The implementation of Generics in Java 1.5 came with a nice advantage: you could code in fancy spanking-new 1.5 generics and still generate classes that were compatible with previous versions of Java!

They did that by enforcing the type safety with generics only at compilation time, but otherwise generate code compatible with Java 1.2+ by removing any parameterised type from the compiled class.

In effect, using generics it is now easier to code type-safe classes, but the checking is not done at runtime. If you find a way to feed your application with instances that do not comply with the intended generics behaviour (in our example, having an Enumeration of, say, String instead of Appender), this will certainly result in a nice ClassCastException!

And that’s the way it is implemented in Java, full stop! No discussion possible (until they decide to cut with previous versions of Java). So why have a warning at all?

The solution

Actually, there is a very simple answer to this (apart from the fact that future versions might not provide backward compatibility)…

It is obvious we are trying to get an Enumeration of Appender instances in order to apply some process on each of them; …but wait!

Appender is an interface… (that’s what got me on the tracks for the solution!)

What you are actually getting is an Enumeration on implementations of Appender; that is, any implementation possible!!!

So really, the code logically needs to be written as follows:

Enumeration<? extends Appender> e = (Enumeration<? extends Appender>)log.getAllAppenders();

That’s right! we want to be able to deal generically with any subtype of Appender… seems soooo easy now with hindsight, isn’t it?

Sphere: Related Content

Leave a Reply

You must be logged in to post a comment.