Gson TypeToken with dynamic ArrayList item type
Since Gson 2.8.0, you can use TypeToken#getParameterized(Type rawType, Type... typeArguments)
to create the TypeToken
, then getType()
should do the trick.
For example:
TypeToken.getParameterized(ArrayList.class, myClass).getType()
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();
}
Option 1 - implement java.lang.reflect.ParameterizedType
yourself and pass it to Gson.
private static class ListParameterizedType implements ParameterizedType {
private Type type;
private ListParameterizedType(Type type) {
this.type = type;
}
@Override
public Type[] getActualTypeArguments() {
return new Type[] {type};
}
@Override
public Type getRawType() {
return ArrayList.class;
}
@Override
public Type getOwnerType() {
return null;
}
// implement equals method too! (as per javadoc)
}
Then simply:
Type type = new ListParameterizedType(clazz);
List<T> list = gson.fromJson(json, type);
Note that as per javadoc, equals method should also be implemented.
Option 2 - (don't do this) reuse gson internal...
This will work too, at least with Gson 2.2.4.
Type type = com.google.gson.internal.$Gson$Types.newParameterizedTypeWithOwner(null, ArrayList.class, clazz);