Preventing the Construction of a "Raw Type" Reference

Viewed 142

The Jackson Core library contains the TypeReference abstract class.

This class implements Comparable. The JavaDoc explains why:

It uses a...

...bogus implementation of Comparable (any such generic interface would do, as long as it forces a method with generic type to be implemented), to ensure that a Type argument is indeed given.

and:

compareTo(): The only reason we define this method (and require implementation of Comparable) is to prevent constructing a reference without type information.

An example of using TypeReference with type information (Map<String, Object>):

String json = "{ \"some_key\": 123 }";
ObjectMapper objectMapper = new ObjectMapper();
TypeReference<Map<String, Integer>> typeReference = new TypeReference<>(){};
Map<String, Integer> map = objectMapper.readValue(json, typeReference);

(The class is abstract, but it contains an implementation of compareTo() - so I don't need to provide one.)

The above technique does not stop me from constructing a reference without type information. The following compiles successfully (although the end result is not useful):

// bad idea - just for illustration:
TypeReference typeReference2 = new TypeReference() {};

What am I missing about the use of Comparable here? It does not prevent code compilation. I don't see how it could.

Compiler warnings are a different matter - I'm wondering specifically about the "prevention" claim.


Background Notes:

If I try to use my raw type typeReference2, it will throw a runtime exception, because of the following check in the constructor:

Type superClass = getClass().getGenericSuperclass();
if (superClass instanceof Class<?>) { // sanity check, should never happen
    throw new IllegalArgumentException("Internal error: TypeReference constructed without actual type information");
}

The Javadoc for the class refers to an article which discusses the above runtime technique. It seems that a comment in that article prompted the inclusion of Comparable in Jackson's TypeReference class:

Rather than check for a type parameter in the constructor, you can make it a syntax error to leave out:

public abstract TypeReference<R> implements Comparable<TypeReference<R>> {
    // ...
    public int compareTo(TypeReference<R> o) {
        // Need a real implementation.
        // Only saying "return 0" for illustration.
        return 0;
    }
}

Now this is legal:

new TypeReference<Object>() { };

But this is a syntax error for not implementing Comparable:

new TypeReference() { };

I do not see this as a syntax error for TypeReference. It compiles OK, and we've been given an implementation in the class already.

0 Answers
Related