我想编写一个泛型函数,用Gson反序列化泛型类型List 这是代码:
private <T> List<T> GetListFromFile(String filename)
{
//Read textfile
BufferedReader reader;
String data="";
try
{
reader = new BufferedReader(new FileReader(filename));
data = reader.readLine();
reader.close();
}
catch (FileNotFoundException ex)
{
}
catch (IOException ex)
{
}
if (data == null)
{
List<T> Spiel = new ArrayList<T>();
return Spiel;
}
else
{
//get list with Deserialise
Gson gson = new Gson();
List<T> something = gson.fromJson(data, new TypeToken<List<T>>(){}.getType());
return something;
}
}
但是这段代码不起作用,我得到一个奇怪的结构但不是我的类型列表
当我使用时:
List<concreteType> something = gson.fromJson(data, new TypeToken<List<T>>(){}.getType());
我的工作是List<concreteType>
!!
但我需要一个通用功能,我该如何解决?
此致 rubiktubik
答案 0 :(得分:8)
使用TypeToken的方法无效。
new TypeToken<ArrayList<T>>()
由于泛型(类型擦除)和反射如何工作,是不可能的。整个TypeToken
hack有效,因为Class#getGenericSuperclass()
执行以下操作
返回表示实体的直接超类的Type (类,接口,基本类型或void)由此类表示。
如果超类是参数化类型,则返回Type对象 必须准确反映源中使用的实际类型参数 代码。
换句话说,如果它看到ArrayList<T>
,那么它将返回ParameterizedType
,你将无法提取类型变量T
将具有的编译时间值了。
Type
和ParameterizedType
都是接口。您可以提供自己实现的实例。
所以,你有两个选择:
选项1:
自己实施java.lang.reflect.ParameterizedType
并将其传递给Gson。
private static class ListParameterizedType implements ParameterizedType {
private Type type;
public 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
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);
}
}
答案 1 :(得分:3)
如果没有将T
(作为Class<T>
)的实际类型传递给您的方法,则无法执行此操作。
但如果您明确传递,则可以为TypeToken
创建List<T>
,如下所示:
private <T> List<T> GetListFromFile(String filename, Class<T> elementType) {
...
TypeToken<ArrayList<T>> token = new TypeToken<ArrayList<T>>() {};
List<T> something = gson.fromJson(data, token.getType());
...
}
另见: