I need to pass the class of a generic type into a class's constructor. The class is SpiceRequest from the RoboSpice Android library for a reference to the constructor.
It seems odd that the class requires passing the generic's class into the contstructor, when it could be accessed from the generic type itself, in this case RESULT.class
, but maybe I'm wrong about this. Anyway, I'm not looking to change the library's code, but rather need to use a generic type for the generic type of SpiceRequest
, Map<String, ? extends Object>
. Here's my code:
SpiceRequest<Map<String, ? extends Object>> request =
new SpiceRequest<Map<String, ? extends Object>>(???) {
...
};
And the signature of the SpiceRequest
constructor:
public SpiceRequest(final Class<RESULT> clazz) {
...
}
For ??? I have tried Map.class
with the compiler error: The constructor SpiceRequest<Map<String,? extends Object>>(Class<Map>) is undefined.
Map<String, ? extends Object>.class
gives the error: Syntax error on tokens, PrimitiveType expected instead
, specifically underlining ? extends Object
. It also gives the same error as Map.class
.
And Map.<String, ? extends Object>class
gives the same compiler error as well.
What is the correct way to get the generic class Class<Map<String, ? extends Object>>
?
Static and non-static generic methods are allowed, as well as generic class constructors. The syntax for a generic method includes a list of type parameters, inside angle brackets, which appears before the method's return type.
A static method can be called from either a class or object reference. We can call it Utils if foo() is a static function in Class Utils. Utils. foo() as well as Utils().
To call a generic method, you need to provide types that will be used during the method invocation. Those types can be passed as an instance of NType objects initialized with particular . NET types.
Generic MethodsAll generic method declarations have a type parameter section delimited by angle brackets (< and >) that precedes the method's return type ( < E > in the next example). Each type parameter section contains one or more type parameters separated by commas.
There are no class literals for concrete parameterized types or wildcard parameterized types. From Angelika Langer's generics tutorial:
Wildcard parameterized types lose their type arguments when they are translated to byte code in a process called type erasure. As a side effect of type erasure, all instantiations of a generic type share the same runtime representation, namely that of the corresponding raw type. In other words, parameterized types do not have type representation of their own. Consequently, there is no point to forming class literals such as
List<?>.class
,List<? extends Number>.class
andList<Long>.class
, since no suchClass
objects exist. Only the raw typeList
has aClass
object that represents its runtime type. It is referred to asList.class
.
There are no class literals for concrete parameterized types for the same reasons, which in a nutshell are type erasure.
For your purposes, you will just need to do an unchecked cast of the class literal:
Class<Map<String, ?>> c = (Class<Map<String, ?>>)(Class<?>)Map.class;
Note that the double cast through Class<?>
is necessary because a direct conversion from Class<Map>
to Class<Map<String, ?>>
is illegal.
this problem is not really related to RoboSpice itself but to a limitation of the Java syntax : there is no litteral that you can use to get the class/type of a parametrized generic type in Java.
If you want to do something like
public class ListTweetRequest extends SpiceRequest<List<Tweet>> {
public ListTweetRequest(Object cacheKey ) {
super( <Here is the problem>, cacheKey );
}
}
then you can't pass the class List<Tweet>.class
to you parent constructor. That's really a Java limitation as generics are realized using type erasure and List<Tweet>.class
has no real meaning in Java.
The best and cleanest work around is to use an intermediate type like :
public class ListTweet extends List<Tweet> {
}
public class ListTweetRequest extends SpiceRequest<ListTweet> {
public ListTweetRequest(Object cacheKey ) {
super( ListTweet.class, cacheKey );
}
}
This has the advantage to provide you with a real type that you can pass to the SpiceRequest's constructor. But beware of obfuscation. In thoses cases, proguard will try to remove the ListTweet class, you have to explicitly preserve it from obfuscation.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With