views:

139

answers:

4

(This is somewhat a followup to my previous question)

I've got a Foo<?> object, foo. Foo<T> is an interface.

How to get the type value hidden behind the <?>?

Note that this is not trivial, as foo can be for example an object of class Bar<String>, where Bar<T> implements Foo<T>, or some anonyomus class implementing interface FloatFoo, where FloatFoo extends Foo<Float>. I need a solution that works in all cases.

Thanks in advance :)

+8  A: 

This is not possible using reflection because Java Generics has the problem of Type Erasure. At runtime the types that have been defined for the generic class Foo have been removed, so using reflection on that class will not yield its generic type. This type information is used only in compilation for type safety.

C# does not have this issue and it is possible to access the templatized type of a Class.

This is a overview of the differences.

linuxuser27
+7  A: 

Well, for short, you can't.

However, what you can do is get the value of <?> when using FloatFoo.

Indeed, from what I remember, generics are not kept in class information.

however, when you create a subtype (be it class or interface) of a generics type, the generics information has to be memorized as it may define some of the subtype's methods signature.

As an example, if your Foo interfaceis declared as it :

public interface Foo<T> {
    public T doIt();
}

Having a

public interface FloatFoo extends Foo<Float>

implies this interface has a

public Float doIt();

method declared.

For that, the compiler has to have the type information. And this information will be reflected in the reflection API by the fact that FloatFoo's super class will have some Type parameters associated to it. Or it least it is what I remember from the few cases I encountered such cases (or elaborated them, as it may sometimes be mandatory)

But you'll have far more complete informations at Angelika's generics FAQ.

Riduidel
the problem is, that `getMethod("doIt").getReturnType()` returns `Object`, and if you would run the method to see what it returned, sometimes you would get a subclass object, and sometimes `null`.
m01
related and maybe helpfull: http://www.artima.com/weblogs/viewpost.jsp?thread=208860
Arne
@m01 The interface trick that Riduidel is mentioning does not always work. It was mentioned as an example of some data being present, but the underlying problem still exists. The link mentioned by Arne references a workaround created by Neal Gaffer, one of the Java compiler devs.
linuxuser27
@Arne thanks, that's what I was looking for !
Riduidel
A: 

I ended up with creating a getType() method in the interface:

Class<T> getType();

Maybe it's not the most elegant solution, but definitely the simplest one.

m01
This still doesn't work if your <T> is, let's say, List<String>. The best you could return is List.class. If the situation gets that complex take a look at the "Super Type Token" pattern: http://gafter.blogspot.com/2006/12/super-type-tokens.html
Michael D
+1  A: 

The final-final (and perhaps the best possible) solution: I refactored my code, so it doesn't need this. I moved all code which needed the type parameter into Foo, so I could provide appropriate implementation within the class. It turned out to be much less code.

m01