rub*_*bik 6 java generics serialization json gson
我想编写一个泛型函数,用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;
}
}
Run Code Online (Sandbox Code Playgroud)
但是这段代码不起作用,我得到一个奇怪的结构,但不是我的类型列表
当我使用时:
List<concreteType> something = gson.fromJson(data, new TypeToken<List<T>>(){}.getType());
Run Code Online (Sandbox Code Playgroud)
我的工作我得到了List<concreteType>
!!
但我需要一个通用功能,我该如何解决?
关心rubiktubik
使用TypeToken的方法不起作用.
new TypeToken<ArrayList<T>>()
Run Code Online (Sandbox Code Playgroud)
由于泛型(类型擦除)和反射如何工作,因此是不可能的.整个TypeToken
黑客的工作原理是因为Class#getGenericSuperclass()
以下内容
返回表示此Class表示的实体(类,接口,基本类型或void)的直接超类的Type.
如果超类是参数化类型,则返回的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)
}
Run Code Online (Sandbox Code Playgroud)
那简单地说:
Type type = new ListParameterizedType(clazz);
List<T> list = gson.fromJson(json, type);
Run Code Online (Sandbox Code Playgroud)
请注意,根据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);
}
}
Run Code Online (Sandbox Code Playgroud)
如果不将T
(as Class<T>
) 的实际类型传递给您的方法,就无法做到这一点。
但是如果你明确地传递它,你可以创建一个TypeToken
forList<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());
...
}
Run Code Online (Sandbox Code Playgroud)
也可以看看: