我有这段代码:
Type typeOfObjectsList = new TypeToken<ArrayList<myClass>>() {}.getType();
List<myClass> objectsList = new Gson().fromJson(json, typeOfObjectsList);
它将JSON字符串转换为List
个对象。
但是现在我希望这个ArrayList
具有动态类型(不仅仅是myClass
),在运行时定义。
ArrayList
的项目类型将使用 reflection 进行定义。
我试过了:
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....}
答案 0 :(得分:40)
自Gson 2.8.0起,您可以使用TypeToken#getParameterized(Type rawType, Type... typeArguments)
创建TypeToken
,然后getType()
就可以了。
例如:
TypeToken.getParameterized(ArrayList.class, myClass).getType()
答案 1 :(得分:38)
您提出的语法无效。以下
new TypeToken<ArrayList<Class.forName(MyClass)>>
无效,因为您正在尝试传递期望类型名称的方法调用。
以下
new TypeToken<ArrayList<T>>()
由于泛型(类型擦除)和反射如何工作,是不可能的。整个TypeToken
hack有效,因为Class#getGenericSuperclass()
执行以下操作
返回表示实体的直接超类的Type (类,接口,基本类型或void)由此类表示。
如果超类是参数化类型,则返回Type对象 必须准确反映源中使用的实际类型参数 代码。
换句话说,如果它看到ArrayList<T>
,那么它将返回ParameterizedType
,你将无法提取类型变量T
将具有的编译时间值了。
Type
和ParameterizedType
都是接口。您可以提供自己实现的实例。
答案 2 :(得分:29)
选项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);
答案 3 :(得分:7)
这对我有用:
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);
}
}
答案 4 :(得分:7)
你可以使用Guava更强大的TypeToken
:
private static <T> Type setModelAndGetCorrespondingList2(Class<T> type) {
return new TypeToken<ArrayList<T>>() {}
.where(new TypeParameter<T>() {}, type)
.getType();
}
答案 5 :(得分:5)
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);
这是一个很好的演示如何在自定义反序列化器中使用它: Deserializing ImmutableList using Gson
答案 6 :(得分:2)
你实际上可以做到。您只需先将数据解析为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;
答案 7 :(得分:1)
在 kotlin 中你可以
inline fun <reified T> parseData(row :String): T{
return Gson().fromJson(row, object: TypeToken<T>(){}.type)
}
答案 8 :(得分:0)
完整的解决方案:
String json = .... //example: mPrefs.getString("list", "");
ArrayList<YouClassName> myTypes = fromJSonList(json, YouClassName.class);
public <YouClassName> ArrayList<YouClassName> fromJSonList(String json, Class<YouClassName> type) {
Gson gson = new Gson();
return gson.fromJson(json, TypeToken.getParameterized(ArrayList.class, type).getType());
}
答案 9 :(得分:0)
inline fun <reified T : Any> T?.json() = this?.let { Gson().toJson(this, T::class.java) }
使用示例:
val list = listOf("1","2","3")
val jsonArrayAsString = list.json()
//output : ["1","2","3"]
val model= Foo(name = "example",email = "t@t.com")
val jsonObjectAsString = model.json()
//output : {"name" : "example", "email" : "t@t.com"}
inline fun <reified T : Any> String?.fromJson(): T? = this?.let {
val type = object : TypeToken<T>() {}.type
Gson().fromJson(this, type)
}
使用示例:
val jsonArrayAsString = "[\"1\",\"2\",\"3\"]"
val list = jsonArrayAsString.fromJson<List<String>>()
val jsonObjectAsString = "{ "name" : "example", "email" : "t@t.com"}"
val model : Foo? = jsonObjectAsString.fromJson()
//or
val model = jsonObjectAsString.fromJson<Foo>()
答案 10 :(得分:0)
实际上我已经制作了扩展函数来解决这个问题,将列表保存到 SharedPrefence 并在应用程序的任何地方检索它们,如下所示:
使用它来将列表保存到 SharedPref。例如:
fun <T> SaveList(key: String?, list: List<T>?) {
val gson = Gson()
val json: String = gson.toJson(list)
getSharedPrefrences(App.getAppContext() as Application).edit().putString(key, json).apply()}
从 sharedPref 中的任何位置返回列表。像这样:
fun Context.getList(key: String): String? {
return getSharedPrefrences(App.getAppContext() as Application).getString(key, null)}
inline fun <reified T : Any> String?.fromJson(): T? = this?.let {
val type = object : TypeToken<T>() {}.type
Gson().fromJson(this, type)}
在保存和从保存的列表中获取列表的用法如下:
saveList(Consts.SLIDERS, it.data)
SetSliderData(this.getList(Consts.SLIDERS).fromJson<MutableList<SliderResponseItem>>()!!)