Eagle11
Eagle11

Reputation: 661

Creating lists of dynamic types

So, I'm working right now on trying to figure out how to parse a large number of different JSON objects without having to hard-code functions to serialize and deserialize each of the objects. I started using Gson, and that has been working pretty well. A problem begins to appear though when I am trying to use a list of objects.

I would like to create a function that will work with any of my data model objects that I can pass a JSONArray and the class type that the JSON contains, so that I would have a call that looks something like this -

response = JSONHelper.createObjectList(jsonArray, DataObject.class);

Btw, I'm not posting from my dev machine, so forgive me if there are a few typos in my code.

I tried to create that effect by writing something like this (inside my JSONHelper class) -

public List createObjectList(JSONArray jsonArray, Class type) {
    Gson gson = new Gson();

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

    List<type> data = gson.fromJson(jsonArray, listType);

    return data;
}

Okay, so obviously that isn't working code, but that is kinda how I wanted to be able to get this to work. I tried several different ways and variations, but I haven't been able to figure out anything that works really nicely.

I am new to the Android/Java world, so i'm still learning the in's and out's of the language. If someone could give me some tips on how I could achieve what I am looking for, it would be very helpful. Thanks.

Upvotes: 0

Views: 218

Answers (1)

Brian Roach
Brian Roach

Reputation: 76908

The answer is: You can't do what you're trying to do in Java because of type erasure.

That's the reason you have to use TypeToken and pass a Type to Gson's fromJson() method; the type information for T isn't available at runtime. Generics in Java are for the most part just compile time type checking.

Ideally you'd like to be able to do this:

public <T> List<T> createList(JsonArray a, Class<T> clazz)
{
    Type t = new TypeToken<List<T>>(){}.getType();
    return new Gson().fromJson(a, t);
}

But you can't, because T gets erased. If you try this you'll find the result completely confusing; you get a List back, but it won't actually contain your class and throw a cast exception.

Effectively, your method would have to look like this:

public <T> List<T> createList(JsonArray a, Type t)
{
    List<T> list = new Gson().fromJson(a, t);
    return list;
}

Which of course would be silly since you're now calling a method you wrote instead of just calling the method in Gson.

Edit to add:

Thinking about it, there's way around this for List types. You can use arrays:

public <T> List<T> createList(JsonArray a, Class<T[]> c)
{
    T[] array = new Gson().fromJson(a, c);
    return Arrays.asList(array);
}

Because you're not trying to rely on the generic type from inside a List and instead are passing an array type for the class... it works. A bit messy, but it works:

List<MyPojo> list = createList(a, MyPojo[].class);

Upvotes: 2

Related Questions