How to call a static class method on a shared object?

I need to pass a generic type class to the class constructor. The SpiceRequest class from RoboSpice Android for reference to the constructor.

It seems strange that a class requires passing the generic class to the counter-constructor when it can be accessed from the most general type, in this case RESULT.class , but maybe I'm wrong about that. In any case, I do not want to change the library code, but rather I should use the generic type for the generic type SpiceRequest , Map<String, ? extends Object> Map<String, ? extends Object> . Here is 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 tried Map.class with a compiler error: The constructor SpiceRequest<Map<String,? extends Object>>(Class<Map>) is undefined. The constructor SpiceRequest<Map<String,? extends Object>>(Class<Map>) is undefined.

Map<String, ? extends Object>.class Map<String, ? extends Object>.class gives an error: Syntax error on tokens, PrimitiveType expected instead , specifically emphasizing ? extends Object ? extends Object . It also gives the same error as Map.class .

And Map.<String, ? extends Object>class Map.<String, ? extends Object>class also gives the same compiler error.

What is the correct way to get the generic class Class<Map<String, ? extends Object>> Class<Map<String, ? extends Object>> ?

+7
source share
4 answers

There are no class literals for specific parameterized types or wildcard parameters. From the generic tutorial of Angelica Langer :

Pattern-dependent wildcard parameters lose their type arguments when they are converted to byte code in a process called type erasure. As a side effect of type erasure, all instances of a common fraction of a type have the same representation of the run time, namely the corresponding type. In other words, parameterized types are not of type representation of their own. Therefore, it makes no sense to form class literals such as List<?>.class , List<? extends Number>.class List<? extends Number>.class and List<Long>.class , since such Class objects exist. Only the original List type has a Class object that represents its runtime type. It is called List.class .

There are no class literals for specific parameterized types for the same reasons that in a nutshell erase the type .

For your purposes, you just need to do an unchecked cast of the class literal:

 Class<Map<String, ?>> c = (Class<Map<String, ?>>)(Class<?>)Map.class; 

Note that double-clicking Class<?> necessary because directly converting from Class<Map> to Class<Map<String, ?>> is illegal.

+5
source

this problem is not actually related to RoboSpice itself, but to the limitation of Java syntax: there is no literator that you can use to get the class / type of a parameterized 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 cannot pass the List<Tweet>.class parent constructor. This is really a Java restriction as generics is implemented using type erasure, and List<Tweet>.class doesn't make any real sense in Java.

The best and cleanest job is to use an intermediate type, for example:

 public class ListTweet extends List<Tweet> { } public class ListTweetRequest extends SpiceRequest<ListTweet> { public ListTweetRequest(Object cacheKey ) { super( ListTweet.class, cacheKey ); } } 

This has the advantage of providing you with a real type that you can pass to the SpiceRequest constructor. But beware of obfuscation. In those cases, proguard will try to remove the ListTweet class, you must explicitly save it from obfuscation.

+4
source

I always guess the erasure, but have you tried just calling it Map.class?

0
source

I had a problem too, and I found a solution similar to @Snicolas.

Take a look at this Robospice-sample-retrofit model example:

https://github.com/octo-online/RoboSpice-samples/blob/release/robospice-sample-retrofit/src/com/octo/android/robospice/sample/retrofit/network/SampleRetrofitSpiceRequest.java

In fact, it is better to inherit not from the raw List interface, but for any subclass, such as ArrayList, etc., otherwise you will have to implement all the methods of the interface.

 import java.util.ArrayList; public class Contributor { public String login; public int contributions; @SuppressWarnings("serial") public static class List extends ArrayList<Contributor> { } } 
0
source

All Articles