具有动态ArrayList项类型的Gson TypeToken
我有这个代码:
Type typeOfObjectsList = new TypeToken<ArrayList>() {}.getType(); List objectsList = new Gson().fromJson(json, typeOfObjectsList);
它将JSON字符串转换为对象List
。 但是现在我希望这个ArrayList
具有动态类型(不仅仅是myClass
),在运行时定义。
ArrayList
的项类型将使用reflection定义。
我试过这个:
private Type setModelAndGetCorrespondingList2(Class type) { Type typeOfObjectsListNew = new TypeToken<ArrayList>() {}.getType(); return typeOfObjectsListNew; }
但它不起作用。 这是例外:
java.sql.SQLException: Fail to convert to internal representation: {....my json....}
您提出的语法无效。 下列
new TypeToken>
因为您尝试传递期望类型名称的方法调用而无效。
下列
new TypeToken>()
因为generics(类型擦除)和reflection的工作方式是不可能的。 整个TypeToken
hack有效,因为Class#getGenericSuperclass()
执行以下操作
返回表示此Class表示的实体(类,接口,基本类型或void)的直接超类的Type。
如果超类是参数化类型,则返回的Type对象必须准确反映源代码中使用的实际类型参数。
换句话说,如果它看到ArrayList
,那么它将返回ParameterizedType
,你将无法提取类型变量T
将具有的编译时间值。
Type
和ParameterizedType
都是接口。 您可以提供自己实现的实例。
选项1 – 自己实现java.lang.reflect.ParameterizedType
并将其传递给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) }
那简单地说:
Type type = new ListParameterizedType(clazz); List list = gson.fromJson(json, type);
请注意,根据javadoc ,还应实现equals方法。
选项2 – (不要这样做)重用gson内部…
这也会起作用,至少与Gson 2.2.4一样。
Type type = com.google.gson.internal.$Gson$Types.newParameterizedTypeWithOwner(null, ArrayList.class, clazz);
从Gson 2.8.0开始,你可以使用TypeToken#getParameterized(Type rawType, Type... typeArguments)
来创建TypeToken
,然后getType()
就可以了。
例如:
TypeToken.getParameterized(ArrayList.class, myClass).getType()
这对我有用:
public List listEntity(Class clazz) throws WsIntegracaoException { try { // Consuming remote method String strJson = getService().listEntity(clazz.getName()); JsonParser parser = new JsonParser(); JsonArray array = parser.parse(strJson).getAsJsonArray(); List lst = new ArrayList (); 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); } }
你可以用Guava更强大的TypeToken
做到这TypeToken
:
private static Type setModelAndGetCorrespondingList2(Class type) { return new TypeToken>() {} .where(new TypeParameter () {}, type) .getType(); }
sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl
工作。 无需自定义实现
Type type = ParameterizedTypeImpl.make(List.class, new Type[]{childrenClazz}, null); List list = gson.fromJson(json, type);
可以与地图和任何其他集合一起使用:
ParameterizedTypeImpl.make(Map.class, new Type[]{String.class, childrenClazz}, null);
这是一个很好的演示如何在自定义反序列化器中使用它: 使用Gson反序列化ImmutableList
你实际上可以做到这一点。 您只需要先将数据解析为JsonArray
,然后单独转换每个对象,并将其添加到List
:
Class dataType; //... JsonElement root = jsonParser.parse(json); List data = new ArrayList<>(); JsonArray rootArray = root.getAsJsonArray(); for (JsonElement json : rootArray) { try { data.add(gson.fromJson(json, dataType)); } catch (Exception e) { e.printStackTrace(); } } return data;