tags:

views:

436

answers:

7

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.

A: 

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

Yaneeve
+2  A: 

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

E.g.

List<String> myList = new ArrayList<String>();
return (Class<List<String>>)myList.getClass();
JRL
doesn't compile here..
Bozho
@Bozho: the springframework link has a different method signature `java.lang.Class<? extends T> getObjectType()`. I've updated my answer to reflect the signature of the OP's question.
JRL
now it compiles ;) with a warning, though
Bozho
A: 

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.

perdian
+5  A: 

You can always cast to what you need, like

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.

Bozho
Where did you find that quote?
skaffman
http://www.angelikalanger.com/GenericsFAQ/FAQSections/ParameterizedTypes.html
Bozho
interesting downvote, 2 weeks after the question was active. Why?
Bozho
A: 

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

fd
+4  A: 

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://code.google.com/p/google-guice/source/browse/trunk/src/com/google/inject/TypeLiteral.java

Kevin Bourrillion
I agree that it's not a good idea, but Java permits it, and if you're trying to implement an interface, you may have no choice in the matter, so we still need a way of doing it (semi-)elegantly.
skaffman
+1  A: 

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