tags:

views:

76

answers:

2

This might be a stupid question, but I just saw a question asking how to create a Type variable for a generic type. The consensus seemed to be that you should have a dummy method returning that type, and then use reflection to get it (in this case he wanted Map<String, String>). Something like this :

public Map<String, String> dummy() { throw new Error(); }

Type mapStringString = Class.forName("ThisClass").getMethod("dummy").getGenericReturnType();

My question is, not having used reflection that much, couldn't you just do something like:

Type mapStringString = new ParameterizedType() {
    public Type getRawType() {
        return Map.class;
    }

    public Type getOwnerType() {
        return null;
    }

    public Type[] getActualTypeArguments() {
        return new Type[] { String.class, String.class };
    }
};

Would this work? If not, why not? And what are some of the dangers/problems if it does (besides being able to return some Type like Integer<String> which is obviously not possible.

+2  A: 

Sure you could, and for most applications it would probably be sufficient.

However, using the first method, you get a more refined object. Let's say for instance that you create an object type1 using the first method, and type2 using the second method. Then type1.equals(type2) would return true (since the first method returns an object that properly implements the equals-method) but type2.equals(type1) would return false (since in the second method, you haven't overridden the equals-method, and are using the implementation from Object).

Same reasoning applies to other (sometimes useful methods) such as toString, hashCode etc. The second method does not provide useful implementations of these.

aioobe
Actually type1's (sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl) implementation of equals seems to cast the parameter of equals to ParameterizedType and then use the interface methods to compare the classes, so `type1.equals(type2)` would return true, though the opposite (`type2.equals(type1)`) would return false; you could implement those as well, but then the code gets a little chunky
Andrei Fierbinteanu
Sure. You could get the same result in method 2 as in method 1, but it requires some more work, as you have noticed.
aioobe
+1  A: 

Actually, I think the simplest way (== least code) to do this would be a dummy interface extending the type your interested in, and then getGenericInterfaces()[0] from its class (use getGenericSuperclass() if you're interested in a class):

private interface MapStringString extends Map<String, String> {}
private static ParameterizedType mapStringString(){
    return (ParameterizedType) MapStringString.class.getGenericInterfaces()[0];
}

It doen't scale well, though, as you have to create a new class for every ParameterizedType you want to represent. I don't see why your implementation wouldn't do (unless there are narrowing casts somewhere), and it does have the appealing benefit that you can make it reusable.

gustafc
While this seems as 'hackish' as the first method I gave, it at least gives better looking code where you try to get the type (just calling the function instead of doing get class, then get method, then get generic return type each time you want to use it).
Andrei Fierbinteanu