8

ジェネリック型 List を Gson で逆シリアル化するジェネリック関数を書きたいのですが、コードは次のとおりです。

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>

しかし、汎用関数が必要なのですが、どうすれば修正できますか?

よろしくルービクトゥビック

4

2 に答える 2

10

TypeToken を使用するアプローチは機能しません。

new TypeToken<ArrayList<T>>() 

ジェネリクス (型消去) とリフレクションのしくみのため、これは不可能です。TypeToken次のようにするため、ハック全体Class#getGenericSuperclass()が機能します

この Class によって表されるエンティティ (クラス、インターフェース、プリミティブ型、または void) の直接のスーパークラスを表す Type を返します。

スーパークラスがパラメーター化された型である場合、返される Type オブジェクトは、ソース コードで使用される実際の型パラメーターを正確に反映する必要があります。

つまり、 が表示された場合ArrayList<T>、それが返され、型変数が持っていたはずParameterizedTypeのコンパイル時の値を抽出できなくなります。T

TypeParameterizedTypeは両方ともインターフェースです。独自の実装のインスタンスを提供できます。

したがって、次の 2 つのオプションがあります。

オプション 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);
    }
}
于 2017-01-25T16:03:28.740 に答える
6

Tメソッドに(as )の実際の型を渡さずにそれを行う方法はありませんClass<T>

ただし、明示的に渡す場合は、次のようにTypeTokenforを作成できます。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());
    ...
}

以下も参照してください。

于 2013-08-19T18:56:03.193 に答える