Reputation: 13947
I want to deserialize an array of complex objects
for instance i have object MyTestObject
public class MyTestObject{
String param1;
String param2;
int param3;
}
now i have an array of objects named MyTestObject
and my json looks like this
{
[
"param1":"something1",
"param2:"something2",
"param3":3
],
[
"param1":"something1",
"param2:"something2",
"param3":3
],
[
"param1":"something1",
"param2:"something2",
"param3":3
]
}
this is my code for desearilization
public static <T> List<T> fromJSON(String json, Class<T> className) {
GsonBuilder builder = new GsonBuilder();
builder.serializeNulls();
Type myType = new TypeToken<List<T>>() {
}.getType();
Gson g1 = builder.create();
List<T> objects = (List<T>) g1.fromJson(json, (Type) myType);
for (T object : objects) {
Log.d(TAG, "object: " + object + " class " + object.getClass());
}
return objects;
}
ArrayList<MyTestObject> objects = fromJSON(myjson,MyTestObject.class);
the array itself gets deserialized correctly, however, the objects inside it are not of the correct class, they are of type com.google.gson.internal.LinkedTreeMap
when i need them to be of type MyTestObject
how do i fix this?
Upvotes: 2
Views: 1728
Reputation: 1478
A sample :
public class Test<T> {
public static void main(String[] args) throws Exception {
new Test<String>().test(String.class);
new Test<Integer>().test(Integer.class);
new Test<Long>().test(Long.class);
}
public void test(Class<T> cls) throws Exception {
TypeToken<?> typeOfT = getGenToken(List.class, cls);
List<?> lst = (List<?>) new Gson().fromJson("[1, 2, 3]", typeOfT.getType());
for (Object o : lst) {
System.out.println("value : " + o + ", type : " + o.getClass());
}
}
static TypeToken<?> getGenToken(final Class<?> raw, final Class<?> gen) throws Exception {
Constructor<ParameterizedTypeImpl> constr = ParameterizedTypeImpl.class.getDeclaredConstructor(Class.class, Type[].class, Type.class);
constr.setAccessible(true);
ParameterizedTypeImpl paramType = constr.newInstance(raw, new Type[] { gen }, null);
return TypeToken.get(paramType);
}
}
ParameterizedTypeImpl
came from sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl
.
Output :
value : 1, type : class java.lang.String
value : 2, type : class java.lang.String
value : 3, type : class java.lang.String
value : 1, type : class java.lang.Integer
value : 2, type : class java.lang.Integer
value : 3, type : class java.lang.Integer
value : 1, type : class java.lang.Long
value : 2, type : class java.lang.Long
value : 3, type : class java.lang.Long
Note : in fact we could replace the wildcar with T
, but that's not usefull here.
Upvotes: 3
Reputation: 1478
You can't use new TypeToken<List<T>>()
, because of type erasure GSon won't know the type of T
.
https://sites.google.com/site/gson/gson-user-guide#TOC-Serializing-and-Deserializing-Generic-Types
You can either provide in a static way T
like
Type myType = new TypeToken<List<Something>>() {
}.getType();
Or build a TypeToken
with a Class<T>
var for the generic. There is no simple way to do this as far as I know. This is how I do it :
static TypeToken<?> getGenToken(final Class<?> raw, final Class<?> gen) throws Exception {
Constructor<ParameterizedTypeImpl> constr = ParameterizedTypeImpl.class.getDeclaredConstructor(Class.class, Type[].class, Type.class);
constr.setAccessible(true);
ParameterizedTypeImpl paramType = constr.newInstance(raw, new Type[] { gen }, null);
return TypeToken.get(paramType);
}
Then you can build the token like this :
Class<T> tClass = ...;
Type myType = new getGenToken<List.class, tClass>()
Upvotes: 1