带有动态ArrayList项类型的Gson TypeToken

我有这个代码:

Type typeOfObjectsList = new TypeToken<ArrayList<myClass>>() {}.getType(); List<myClass> objectsList = new Gson().fromJson(json, typeOfObjectsList); 

它将JSON字符串转换为对象List 。 但是现在我想要在运行时定义一个动态类型的ArrayList (不只是myClass )。

ArrayList的项目类型将被反射定义。

我试过这个:

  private <T> Type setModelAndGetCorrespondingList2(Class<T> type) { Type typeOfObjectsListNew = new TypeToken<ArrayList<T>>() {}.getType(); return typeOfObjectsListNew; } 

但它不起作用。 这是例外:

 java.sql.SQLException: Fail to convert to internal representation: {....my json....} 

你提出的语法是无效的。 下列

 new TypeToken<ArrayList<Class.forName(MyClass)>> 

是无效的,因为你正在尝试传递一个方法调用的地方类型名称的预期。

下列

 new TypeToken<ArrayList<T>>() 

是不可能的,因为泛型(类型擦除)和反射是如何工作的。 整个TypeToken黑客工作,因为Class#getGenericSuperclass()做以下

返回表示由此类表示的实体(类,接口,基元类型或void)的直接超类的Type。

如果超类是参数化类型,则返回的Type对象必须准确反映源代码中使用的实际类型参数。

换句话说,如果它看到ArrayList<T> ,它将返回ParameterizedType ,您将无法提取类型变量T将具有的编译时间值。

TypeParameterizedType都是接口。 你可以提供你自己的实现的一个实例。

选项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<T> 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); 

这对我工作:

 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); } } 

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

你可以用Guava更强大的TypeToken来做到这TypeToken

 private static <T> Type setModelAndGetCorrespondingList2(Class<T> type) { return new TypeToken<ArrayList<T>>() {} .where(new TypeParameter<T>() {}, type) .getType(); } 

Sinnce gson 2.8.0 ,你可以使用TypeToken#getParametized((Type rawType, Type... typeArguments))来创建typeToken ,那么getType()可以实现。

例如:

 TypeToken.getParameterized(ArrayList.class, myClass).getType(); 

你实际上可以做到这一点。 你只需要首先将数据解析到JsonArray ,然后单独转换每个对象,并将其添加到List

 Class<T> dataType; //... JsonElement root = jsonParser.parse(json); List<T> 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;