Inadequate Java Generics

Generics are so nice to have. It's a shame that Java, in hands-waving reference to backwards-compatibility, made generics so slipshod as to be almost useless for anything more complicated that List<String>. Let me walk you through an example; after just a few levels, the whole thing falls apart. You tell me where I've gone wrong, because I can't make out the solution.

Let's say that we're creating a new serialization data model and we want to represent the types available using a Java class. (We want to use this data model across platforms, so we want to make types agnostic to the impelementing language.) Let's call this CustomType<V>, using V to represent the Java type that actually holds the value. For example, we might have BOOLEAN implements CustomType<Boolean>, meaning that the BOOLEAN type in the serialized file will be represented in Java using the Boolean type.

So how do we create this BOOLEAN? Let's make an enum:

enum DataModelType{STRING, NUMBER, BOOLEAN};

But each enum instance cannot implement an interface! That is, here BOOLEAN will not implement CustomType<Boolean>. Enums are out, so let's just create a class DataModelType<V> implements CustomType<V>, make its constructor private, and create static instances for STRING<String>, BOOLEAN<Boolean>, and NUMBER<Number>.

Now let's make a property that can indicate a name and a data type. We want to make a general base class parser that can parse any one of serveral data models (with their own set of custom types):

public class Property<V, T extends CustomType<V>>
{
public String getName() {…}
public T getType() {
}
public V getValue() {
}
}

Obviously we don't want to give one of these things a type that produces another value, so we use <V, T extends CustomType<V>>. Then comes the world of hurt.

Let's go back to our DataModelType<V> implements CustomType<V> and try to iterate through an array of properties. Oh wait—we can't have an array of generics in Java! So let's have a list of them instead:

List<Property<?, DataModelType<?> properties=new ArrayList
List<Property<?, DataModelType<?>>;
for(Property<?, DataModelType<?>> property:properties)
{
processProperty(property);
}

Fine—we're iterating the properties and sending them to be processed in some way. But let's look at the processing method. As mentioned earlier, we want to make sure a type is being passed in for which the value type matches the value. So the method looks like this:

public <V, T extends CustomType<V>> void processProperty(Property<V, T> property);

Wonderful. Except that this won't compile, because our Property<?, DataModelType<?>> from the list won't capture the wildcard and understand that both ?'s represent the same type. So how do we iterate through these things? Java won't let us introduce a placeholder generic variable (as we do with V in the processProperty() method above) in the middle of the method implementation. We could cast the variable before we send it to processProperty()—but what do we cast it to?

But it gets much worse. Let's say that we have a base parser class Parser<T extends CustomType<?>> and it has some method to parse the property from the data model serialization:

protected abstract <V, TT extends T<V>> Property<V, TT> createProperty(String name,
TT type, Class<V> valueClass, V value);

In our implementation for the parser subclass, DataModelParser<T extends DataModelType<V>>, we override that method like this:

protected <V, TT extends DataModelType<V>> Property<V, TT> createProperty(String name,
TT type, Class<V> valueClass, V value);

But Eclipse 3.4 gives me an error, saying that erasure will give me the same method signature but that with generics the methods aren't really the same. Why not? Doesn't the abstract version say that TT extends T<V>, where T extends CustomType<V>? In the derived parser class, didn't we say that the T extends CustomType<V> is actually DataModelType<V>? So we should be able to substitute TT extends (T<V> extends CustomType<V>) with TT extends CustomType<V>. But no, it doesn't work.

Just so you'll know what does work, this is what Eclipse suggests:

protected <V, TT extends CustomType<V>> Property<V, TT> createProperty(String name,
TT type, Class<V> valueClass, V value);

But what happened to T, which in the derived class I've specified to be DataModelType<?>?

Java generics are conceptually wonderful. The way Java implemented them, in practice they quickly desintegrate into a horrible mess. Unless you are content with List<String>.