How to create a class literal of a known type: Class<List<String>>

JavaGenericsJls

Java Problem Overview


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.

Java Solutions


Solution 1 - Java

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.

Solution 2 - Java

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

Solution 3 - Java

You can implement that method like this:

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

Solution 4 - Java

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);
}

Solution 5 - Java

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

E.g.

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

Solution 6 - Java

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

Solution 7 - Java

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.

Solution 8 - Java

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>

Solution 9 - Java

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];
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionskaffmanView Question on Stackoverflow
Solution 1 - JavaBozhoView Answer on Stackoverflow
Solution 2 - JavaKevin BourrillionView Answer on Stackoverflow
Solution 3 - JavaSaeed ZarinfamView Answer on Stackoverflow
Solution 4 - JavafinnwView Answer on Stackoverflow
Solution 5 - JavaJRLView Answer on Stackoverflow
Solution 6 - JavaMike TunnicliffeView Answer on Stackoverflow
Solution 7 - JavaChristian SeifertView Answer on Stackoverflow
Solution 8 - JavamaziView Answer on Stackoverflow
Solution 9 - JavaLukas Z.View Answer on Stackoverflow