5

I want to go from a TypeReference<E> object to a Class<E> object in Java, without using casting. I require the usage of TypeReference because of the way my code uses Jackson and I need Class object because I want to use it to infer a type into one of my other Generic Classes in my app.

I know that TypeReference.getType() will return a java.lang.reflect.Type object. Basically, if I can find out a way to use code without casting to get from Type to Class, then I have figured out my problem.

Javadoc References:

ecbrodie
  • 11,246
  • 21
  • 71
  • 120
  • `Type` is an interface, not an object, whereas `Class` is a subclass of `Object`. – doublesharp Oct 31 '12 at 19:39
  • 1
    I know that. But my question was how to go from `TypeReference` to `Class`. In only mentioned about the `Type` interface in case it assist someone solving the problem. – ecbrodie Oct 31 '12 at 19:40
  • Isn't `Type` representing a type without any classloader information? So if it points to class `Foo`, it could mean any of the actual `Foo` classes loaded by different classloaders? – biziclop Oct 31 '12 at 19:41
  • `TypeReference.getClass()` will give you the `Class`, but you can't really go from a `Type` to a `Class`. – doublesharp Oct 31 '12 at 19:42
  • 1
    @doublesharp: `TypeReference.getClass()` will return the class object representing `TypeReference`, not representing the generic type. – ecbrodie Oct 31 '12 at 19:43
  • 1
    But technically `Class` implements the `Type` interface, so a simple cast should do the job. – biziclop Oct 31 '12 at 19:44
  • @ecbrodie You need to get the parameterized `Type` of `TypeReference`? – doublesharp Oct 31 '12 at 19:45
  • @biziclop: Doing so will give me the warning: "Class is a raw type. References to generic type Class should be parameterized" – ecbrodie Oct 31 '12 at 19:52
  • @ecbrodie Well, you can cast it to `Class>` then. Or you can just ignore the warning. – biziclop Oct 31 '12 at 20:03
  • 1
    This might be useful: http://docs.oracle.com/javase/tutorial/java/generics/restrictions.html#createObjects – doublesharp Oct 31 '12 at 20:08
  • It was. I now have warning-free code. I'm relying more on wildcards (as in `MyObjectType>` instead of `MyObjectType`). Thanks. – ecbrodie Oct 31 '12 at 20:48

2 Answers2

12

You can not cast it: this is very basic Java question -- TypeReference and Class do not derive from same base class so it is against language definition.

But if I guess correctly what you trying to achieve, you can convert raw (type-erased) class by using JavaType:

JavaType type = mapper.getTypeFactory().constructType(ref);
Class<?> cls = type.getRawClass();

You can construct JavaType out of TypeReference, Class, or even just basic JDK Type.

StaxMan
  • 113,358
  • 34
  • 211
  • 239
  • Which package/jar is `JavaType` from? – ecbrodie Nov 01 '12 at 12:10
  • Nevermind...it is from Jackson. However, I am not sure what class type your `mapper` object is. It isn't `ObjectMapper`; I can't find an `ObjectMaper.getTypeFactory()` method. Instead, my solution that I derive from your is `TypeFactory.defaultInstance().constructType(typeReference).getRawClass()`. Thanks. – ecbrodie Nov 01 '12 at 12:15
  • `ObjectMapper` has `getTypeFactory()` (see http://fasterxml.github.com/jackson-databind/javadoc/2.1.0/com/fasterxml/jackson/databind/ObjectMapper.html) but maybe older versions did not expose it. You can use defaultInstance if so. – StaxMan Nov 01 '12 at 16:07
  • Hold on a sec...that is Jackson by *FasterXML*, not *Codehaus*. Which version of Jackson is the official one? – ecbrodie Nov 01 '12 at 18:05
  • Jackson moved from Codehaus repository to GitHub for 2.x. So Codehaus has old (1.9), github has new. And new has Java package under `com.fasterxml`. Both are official, just different Java packages. – StaxMan Nov 02 '12 at 01:52
4

I don't see any solution without casting. However, here is a solution with kind of generic casting. Maybe this can help, too:

public class Converter {
    public static <T> Class<T> convert(TypeReference<T> ref) {
        return (Class<T>)((ParameterizedType) ref.getType()).getRawType();
    }
}

However this is a framework method. The signature is fully type save and it converts to a class containing all the 'super type token' information Neal Gafter mentions in his blog entry that's delivered the idea of TypeReference. By that it keeps your business code clean and type save.

Usage would then (Here you can't see the cast...;-):

Class<List<String>> typ = Converter.convert(new TypeReference<List<String>>() {});
System.out.println(typ);

With output (Of course the instance is type ereased even though the code shows the String...):

interface java.util.List
Bernd Ebertz
  • 1,317
  • 8
  • 10