Gson TypeToken with dynamic ArrayList item type
The syntax you are proposing is invalid. The following
new TypeToken<ArrayList<Class.forName(MyClass)>>
is invalid because you're trying to pass a method invocation where a type name is expected.
The following
new TypeToken<ArrayList<T>>()
is not possible because of how generics (type erasure) and reflection works. The whole TypeToken
hack works because Class#getGenericSuperclass()
does the following
Returns the Type representing the direct superclass of the entity
(class, interface, primitive type or void) represented by this Class.If the superclass is a parameterized type, the Type object returned
must accurately reflect the actual type parameters used in the source
code.
In other words, if it sees ArrayList<T>
, that's the ParameterizedType
it will return and you won't be able to extract the compile time value that the type variable T
would have had.
Type
and ParameterizedType
are both interfaces. You can provide an instance of your own implementation (define a class that implements either interface and overrides its methods) or use one of the helpful factory methods that TypeToken
provides in its latest versions. For example,
private Type setModelAndGetCorrespondingList2(Class<?> typeArgument) {
return TypeToken.getParameterized(ArrayList.class, typeArgument).getType();
}
Deserialize a List T object with Gson?
Method to deserialize generic collection:
import java.lang.reflect.Type;
import com.google.gson.reflect.TypeToken;
...
Type listType = new TypeToken<ArrayList<YourClass>>(){}.getType();
List<YourClass> yourClassList = new Gson().fromJson(jsonArray, listType);
Since several people in the comments have mentioned it, here's an explanation of how the TypeToken
class is being used. The construction new TypeToken<...>() {}.getType()
captures a compile-time type (between the <
and >
) into a runtime java.lang.reflect.Type
object. Unlike a Class
object, which can only represent a raw (erased) type, the Type
object can represent any type in the Java language, including a parameterized instantiation of a generic type.
The TypeToken
class itself does not have a public constructor, because you're not supposed to construct it directly. Instead, you always construct an anonymous subclass (hence the {}
, which is a necessary part of this expression).
Due to type erasure, the TypeToken
class is only able to capture types that are fully known at compile time. (That is, you can't do new TypeToken<List<T>>() {}.getType()
for a type parameter T
.)
For more information, see the documentation for the TypeToken
class.
How to set an ArrayList Type dynamically using the class name?
So, from what I understand you need to deserialize list of objects but type isn't known on compile time but you are providing it dynamically?
You probably want to use something like that for your type:
TypeToken.getParameterized(List.class, Class.forName("foo.bar.MyDynamicType"))
This will create same type as
new TypeToken<List<MyDynamicType>>(){}.getType()
Gson deserialize generic list into a generic method
SOLUTION - THIS WORKED FOR ME: Gson TypeToken with dynamic ArrayList item type
public <T> List<T> listEntity(Class<T> clazz)
throws WsIntegracaoException {
try {
// Consuming remote method
String strJson = getService().listEntity(clazz.getName());
JsonParser parser = new JsonParser();
JsonArray array = parser.parse(strJson).getAsJsonArray();
List<T> lst = new ArrayList<T>();
for(final JsonElement json: array){
T entity = GSON.fromJson(json, clazz);
lst.add(entity);
}
return lst;
} catch (Exception e) {
throw new WsIntegracaoException(
"WS method error [listEntity()]", e);
}
}
Error casting TypeToken to Type when deserializing with gson
Well you're calling TypeToken.get
, which returns a TypeToken
- not a Type
. in the example you're showing which works, it's using TypeToken.getType()
, which returns a Type
.
So you could use:
return g.fromJson(data, TypeToken.get(new ArrayList<T>().getClass()).getType());
... and that would return you a Type
, but it may not be what you actually want. In particular, due to type erasure that will return you the same type whatever T
you specify from the call site. If you want the type to really reflect ArrayList<T>
, you'll need to pass the class into the method, although I'm not entirely sure where to go from there. (The Java reflection API isn't terribly clear when it comes to generics, in my experience.)
As an aside, I'd expect a method called arrayType
to have something to do with arrays, not ArrayList
.
Related Topics
Ssl Handshake Alert: Unrecognized_Name Error Since Upgrade to Java 1.7.0
How to Schedule a Periodic Task in Java
Java Switch Statement: Constant Expression Required, But It Is Constant
Replace String With Another in Java
How to Change a Jfreechart'S Size
Failed to Load the Jni Shared Library (Jdk)
Deserialize a List≪T≫ Object With Gson
Find Where Java Class Is Loaded From
Java: How to Get a Class Literal from a Generic Type
Can You Use @Autowired With Static Fields
How to Get the First Day of the Current Week and Month
Change File Owner Group Under Linux with Java.Nio.Files
How to Support Both Ipv4 & Ipv6 on Java