Question

Take the following:

public Class<List<String>> getObjectType() {
    // what can I return here?
}

What class literal expression can I return from this method which will satisfy the generics and compile? List.class won't compile, and neither will List.<String>class.

If you're wondering "why", I'm writing an implementation of Spring's FactoryBean<List<String>>, which requires me to implement Class<List<String>> getObjectType(). However, this is not a Spring question.

edit: My plaintive cries have been heard by the powers that be at SpringSource, and so Spring 3.0.1 will have the return type of getObjectType() changed to Class<?>, which neatly avoids the problem.

Was it helpful?

Solution

You can always cast to what you need, like this

return (Class<List<String>>) new ArrayList<String>().getClass();

or

return (Class<List<String>>) Collections.<String>emptyList().getClass();

But I assume that's not what you are after. Well it works, with a warning, but it isn't exactly "beautiful".

I just found this

Why is there no class literal for wildcard parameterized types?

Because a wildcard parameterized type has no exact runtime type representation.

So casting might be the only way to go.

OTHER TIPS

You should never use the construct Class<List<String>>. It is nonsensical, and should produce a warning in Java (but doesn't). Class instances always represent raw types, so you can have Class<List>; that's it. If you want something to represent a reified generic type like List<String>, you need a "super type token" like Guice uses:

http://google-guice.googlecode.com/git/javadoc/com/google/inject/TypeLiteral.html

The existence of a Class<List<String>> is inherently dangerous. here's why:

// This statement generates a warning - for a reason...
Class<List<String>> unsafeListClass = (Class<List<String>>) (Class<?>) List.class;

List<Integer> integerList = new ArrayList<Integer>(); // Ok
integerList.add(42); // Ok

System.out.println(unsafeListClass.isInstance(integerList)); // Prints "true".
List<String> stringList =
   unsafeListClass.cast(integerList); // Succeeds, with no warning!
stringList.add("Hello, World!"); // Also succeeds with no warning

for (int x: integerList) {
    // Compiles without warning, but throws ClassCastException at runtime
    System.out.println(100-x);
}

Found this link on springframework.org which gives some insight.

E.g.

List<String> myList = new ArrayList<String>();
return (Class<List<String>>)myList.getClass();

You can implement that method like this:

public Class<List<String>> getObjectType() {
    return (Class<List<String>>) ((Class)List.class);
}

Check out this discussion on the SUN forums:

http://forums.sun.com/thread.jspa?threadID=5253007

And the referenced blog post that describes a work around by using "super type tokens":

http://gafter.blogspot.com/2006/12/super-type-tokens.html

I'm not sure if this is possible at all, since any class literal will be compiled to Class.forName(...) and since this happens at runtime there is no generic information left.

I am not sure but the following question I asked might be of relevance to you...

java generics type parameters and operations on those types

What about this:

public class TestMain {
    public static void main(String[] args) throws Exception {
        Type type = TestMain.class.getMethod("dummy").getGenericReturnType();
        System.out.println("type = " + type);
    }

    public List<Integer> dummy() {return null;}
}

This prints:

type = java.util.List<java.lang.Integer>

The following approach is problematic:

> public Class<List<String>> getModelType() {
>   return (Class<List<String>>) new ArrayList<String>().getClass();
> }

e.g. if you want to test whether an object say of type

org.eclipse.emf.common.util.BasicEList<String> 

is of type

List<String> 

based on the result of the aforementioned getModelType() approach, for example:

BasicEList<String> fromObject = ...;
if (getModelType().isAssignableFrom(fromObject.getClass())) {
    transferFromModelToUi(getModelType().cast(fromObject));
}

it will result in false whereas it should be true because both objects implement the interface List (since getModelType() returns a Class object of type List and not ArrayList).

Here is an approach that worked for me (a bit cumbersome but leads to correct results in the example above, could be moved to a static initializer):

public Class<List<String>> getModelType() {
    Class<?> arrayListClass = new ArrayList<String>().getClass();
    Class<?>[] interfaces = arrayListClass.getInterfaces();
    int index = 0;
    for (int i = 0; i < interfaces.length; i++) {
        if (interfaces[i].equals(List.class)) {
            index = i;
            break;
        }
    }
    return (Class<List<String>>) interfaces[index];
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top