在Gson中反序列化通用列表

时间:2013-08-19 18:27:18

标签: java json generics serialization 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;
        }
    }

但是这段代码不起作用,我得到一个奇怪的结构但不是我的类型列表

当我使用时:

List<concreteType> something = gson.fromJson(data, new TypeToken<List<T>>(){}.getType());

我的工作是List<concreteType> !!

但我需要一个通用功能,我该如何解决?

此致 rubiktubik

2 个答案:

答案 0 :(得分:8)

使用TypeToken的方法无效。

new TypeToken<ArrayList<T>>() 
由于泛型(类型擦除)和反射如何工作,

是不可能的。整个TypeToken hack有效,因为Class#getGenericSuperclass()执行以下操作

  

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

     

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

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

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

所以,你有两个选择:

选项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());
    ...
}

另见: