Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

accessing parameterized type information at runtime [duplicate]

Possible Duplicate:
Why are not all type information erased in Java at runtime?

Java's generics are implemented via type erasure, so I thought it was no possible to get any information about the parameterized type at runtime. However, I found the following class in the Jackson library.

(I've simplified the class slightly for the sake of this example)

public abstract class TypeReference<T> {
    final Type _type;

    protected TypeReference() {
        Type superClass = getClass().getGenericSuperclass();
        _type = ((ParameterizedType) superClass).getActualTypeArguments()[0];
    }

    public Type getType() { return _type; }

}

The class provides access to it's parameterized type as the following test demonstrates:

void testTypeReference() {
    // notice that we're instantiating an anonymous subclass of TypeReference
    TypeReference<CurrencyDto> tr = new TypeReference<CurrencyDto>() {};
    assert tr.getType() == CurrencyDto.class
} 

This class illustrates that actual type parameters can be retrieved at runtime (using reflection), how is this consistent with the notion that Java Generics are implemented via type erasure?

like image 976
Dónal Avatar asked Jun 09 '11 16:06

Dónal


2 Answers

Concrete type argument information is stored in class files when it's known at compile time. For example, if you have a class with a method that returns List<String> (not List<T>!) that information will be available at runtime. Similarly, if you have a class:

public class Foo extends Bar<String> {
}

the type argument String is hardcoded in to Foo at compile time. The TypeReference class (and all similar constructs, such as TypeLiteral in Guice and TypeToken in Gson) utilizes this fact by requiring you to make an anonymous subclass of it in your code. When you do this, an actual class file will be generated with that information present, just as with the Foo example above.

For more information, see Neal Gafter's blog post here.

Type erasure more refers to the fact that you can't get information on the actual type arguments to an instance of a generic type at runtime (note that Foo, a subclass of Bar<String>, has no type variables and is not generic). For example, if you create an instance of the generic type ArrayList<E>:

List<String> foo = new ArrayList<String>();

no type information is stored in that object. So when you pass it to some other method:

public <T> T foo(List<T> list)

there's no way to find out what T is.

like image 76
ColinD Avatar answered Oct 17 '22 10:10

ColinD


It is really quite simple: you can not get generic information from value INSTANCES, but you can get it from TYPES (classes), with some restrictions. Specifically, there are 3 places where generic type information is available (see http://www.cowtowncoder.com/blog/archives/2008/12/entry_126.html for details); on super-class/interface declaration (parameterization of super type), on field declarations, and and on method (argument, return type) declarations.

In case of TypeReference what happens is that you create an anonymous type with specified super type; and this information will then be available since that anonymous type (class) is passed.

like image 38
StaxMan Avatar answered Oct 17 '22 12:10

StaxMan