Gson Typetoken with Dynamic Arraylist Item Type

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



Leave a reply



Submit