简体   繁体   中英

Java, Gson, Lists and Generics

I have seen some solution to this problem as long as lists are not involved, so I am pushing my luck in order to see if something can be done.

I'm looking to factorize some heavy duplicated code using generics. I have trouble who are probably related to type-erasure. First of all, here is a sample of duplicated code:

    private void readsFoo() throws Exception {
    JsonArray jsonArray = getJsonArray(foo_field);

    Type listType = new TypeToken<List<Foo>>() {
    }.getType();

    List<Foo> fooList= gson.fromJson(jsonArray, listType);

    for (Foo foo : fooList) {
        .....
    }
}

private void readsGoo() throws Exception {
    JsonArray jsonArray = getJsonArray(goo_field);

    Type listType = new TypeToken<List<Goo>>() {
    }.getType();

    List<Goo> gooList= gson.fromJson(jsonArray, listType);

    for (Goo goo : gooList) {
        .....
    }
}

Now, here is the code I produced myself:

private void readsFoo() throws Exception {
    JsonArray jsonArray = getJsonArray(foo_field);
    List<Foo> fooList = getElementsList(jsonArray);

    for (Foo foo: fooList ) {
       .....
    }
}

private <T> List<T> getElementsList(JsonArray iArray)
{
    Type listType = new TypeToken<List<T>>() {}.getType();
    validateJsonElement(listType, "In getElementsList: Unable to find field TypeTokens");

    List<T> list = gson.fromJson(iArray, listType);
    validateJsonElement(list, "In getElementsList: Unable to find list from Json");

    return list;
}

At runtime, I got the following error: java.lang.ClassCastException: com.google.gson.internal.LinkedTreeMap cannot be cast to ....json.Foo

Is there any way to solve this problem ? Because frankly I do hate not reusable code. Thanks !

Basically, a TypeToken can not be made with generic type. You could pass it as an argument instead:

private void readsFoo() throws Exception {
    JsonArray jsonArray = getJsonArray(foo_field);
    List<Foo> fooList = getElementsList(jsonArray, new TypeToken<List<Foo>>(){});

    for (Foo foo: fooList ) {
       .....
    }
}

private <T> List<T> getElementsList(JsonArray iArray, TypeToken<List<T>> tt)
{
    Type listType = tt.getType();
    validateJsonElement(listType, "In getElementsList: Unable to find field TypeTokens");

    List<T> list = gson.fromJson(iArray, listType);
    validateJsonElement(list, "In getElementsList: Unable to find list from Json");

    return list;
}

You are right about the erasure. Since T is erased, the TypeToken you create will hold the type List<T> instead of List<Foo> , which does not hold any information.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM