5

I have my json as:

{
   "status": 200,
   "data": [
       {
            "catId": 638,
            "catName": "Helena Bonham Carter",
            "catUniqueName": "helena-bonham-carter",
            "catSlug": ""
       },
       {
        ...
       }
   ]
}

My Category model as:

public class Category {

    private double catId;
    private String catName;
    private String catUniqueName;
    private String catSlug;
}

And my gson custom deserializer is as follows:

Type listType = new TypeToken<ArrayList<Category>>(){}.getType();

Gson gson = new GsonBuilder()
            .registerTypeAdapter(listType, new CategoryDeserializer())
            .create();

private class CategoryDeserializer implements JsonDeserializer {
    @Override
    public Category deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
            throws JsonParseException {
        Gson gson = new Gson();
        return gson.fromJson(((JsonObject) json).get("data"), typeOfT);
    }
}

I am using Retrofit library which uses gson to serialize/deserialize json objects. I pass this custom gson deserializer to retrofit but it gives me an error. Can you tell me where I am going wrong while desrializing?

Error:

java.util.ArrayList cannot be cast to com.compzets.app.models.Category

Expected Result:

I want ArrayList of Category from json.

Ram Patra
  • 16,266
  • 13
  • 66
  • 81
  • You should say what exact error you get. Also your JSON is invalid: all member names should be in quotes ("status", "catId" etc.) – Tommi Dec 27 '14 at 11:10
  • @Tommi I edited the question, please check! – Ram Patra Dec 27 '14 at 11:16
  • Wouldn't it be easier to create super-class with `public int status` and `public ArrayList data`? Check sample in accepted answer for [this question](http://stackoverflow.com/questions/3763937/gson-and-deserializing-an-array-of-objects-with-arrays-in-it) – Tommi Dec 27 '14 at 11:30
  • I can go with that but i was looking for a better solution, creating wrapper objects just for gson serialization/deserialization isn't the way to go. – Ram Patra Dec 27 '14 at 12:15
  • 1
    Unfortunately, I cannot setup environment to run test project right now, so I can only make some guesses. Your deserializer method you're overriding returns Category instance (not array or arraylist of categories). However, when you get json.get("data") JSON string contains array (according to your sample data), and your TypeToken is generic collection of categories. So it looks like you're trying to return list of Categories, when one Category instance is expected. That's why you get cast error. Side note: I belive that create wrapper object IS better solution you're looking for. – Tommi Dec 27 '14 at 12:47
  • I found the error, changing the return type of `deserialize` from `Category` to `ArrayList` worked. Thanks for pointing that out. So this means we can go with this approach instead of creating wrapper objects. – Ram Patra Dec 27 '14 at 12:55

2 Answers2

3

Changing the return type of deserialize() from Category to ArrayList<Category> solved the issue. Rest of the code is correct.

Ram Patra
  • 16,266
  • 13
  • 66
  • 81
2

It would appear you're just trying to only extract a List of your Category objects from the JSON. You need your deserializer to do that, and use TypeToken accordingly to register your deserializer.

Here's a complete working example. Obviously you can change the class scoping as needed; I changed them to make it a single file example.

public class App 
{
    public static void main( String[] args )
    {
        String json = "{\n" +
            "   \"status\": 200,\n" +
            "   \"data\": [\n" +
            "       {\n" +
            "            \"catId\": 638,\n" +
            "            \"catName\": \"Helena Bonham Carter\",\n" +
            "            \"catUniqueName\": \"helena-bonham-carter\",\n" +
            "            \"catSlug\": \"\"\n" +
            "       }\n" +
            "   ]\n" +
            "}";

        Type listType = new TypeToken<List<Category>>(){}.getType();
        Gson gson = new GsonBuilder().registerTypeAdapter(listType, new CategoryDeserializer()).create();

        List<Category> list = gson.fromJson(json, listType);

        for (Category c : list)
        {
            System.out.println("CatId: " + c.catId);
        }


    }

    public static class CategoryDeserializer implements JsonDeserializer<List<Category>>
    {

        public List<Category> deserialize(JsonElement je, Type type, JsonDeserializationContext jdc) throws JsonParseException
        {
            JsonArray data = je.getAsJsonObject().getAsJsonArray("data");
            ArrayList<Category> myList = new ArrayList<Category>();

            for (JsonElement e : data)
            {
                myList.add((Category)jdc.deserialize(e, Category.class));
            }

            return myList;

        }

    }

    public static class Category
    {
        public double catId;
        public String catName;
        public String catUniqueName;
        public String catSlug;
    }

}

Output:

CatId: 638.0

Nikola Despotoski
  • 49,966
  • 15
  • 119
  • 148
Brian Roach
  • 76,169
  • 12
  • 136
  • 161
  • Thank you very much for the answer, actually my code was correct except for the return type of `deserialize`. I changed it to `ArrayList` and is now working fine. Anyways thanks a ton for the help. – Ram Patra Dec 27 '14 at 18:58