How to grab JSON Array and use gson to parse each json object? (Retrofit)

24,720

Solution 1

I ended up just calling in the callback a list of the customObject and it did the job...

new Callback<List<ObjResponse>>() {

Solution 2

I originally had trouble getting an idea of how the OP solved his problem but, after days of debugging I have finally figured out how to solve this issue.

So you essentially have data in the format like so (JSON Array of JSON Objects):

[
    {
      ...
    }
] 

Your class that models the data and contains the getter and setter methods are nothing more than your typical POJO.

public class Person implements Serializable {
    @SerializedName("Exact format of your json field name goes here")
    private String firstName;

    // Getters and Setters....
}

In your interface that contains your RESTful annotations you want to convert your call from:

Before:

public interface APInterface {
    @GET("SOME URL TO YOUR JSON ARRAY")
    Call<Person>(...)
}

After:

public interface APInterface {
    @GET("SOME URL TO YOUR JSON ARRAY")
    Call<List<Person>>(...)
}

In your android activity you want to convert all calls in the form of Call<Person> to Call<List<Person>>

Finally when making the initial asynchronous request call, you will want to convert your callbacks like so.

call.enqueue(new Callback<List<Person>>() {
    @Override
    public void onResponse(Call<List<Person>> call, Response<List<Person>> response) {

        if(response.isSuccessful()){
            List<Person> person = response.body();

           // Can iterate through list and grab Getters from POJO
           for(Person p: person){...}


        } else {
            // Error response...
        }

    }

    @Override
    public void onFailure(Call<List<Person>> call, Throwable t) {...}
});

Hope this helps others whom are lost from the accepted answer above.

Solution 3

This can also work by just passing an array of response objects. So if this is your response object:

public class CustomUserResponse {
    public String firstName;
    public String lastName;
    ...
}

You can use related syntax, depending on how you use the callbacks. Such as:

new Callback<CustomUserResponse[]>(){
    @Override
    public void success(CustomUserResponse[] customUserResponses, Response rawResponse) {

    }

    @Override
    public void failure(RetrofitError error) {

    }
};

OR

public class GetUserCommand implements Callback<CustomUserResponse[]> { ...

Put simply, in every place where you normally replace T with a response class, replace it with an array, instead as in CustomUserResponse[].


NOTE: to avoid confusing errors, be sure to also use an array in the Retrofit interface definition:

@POST ( "/users" )
public void listUsers(@Body GetUsersRequest request, Callback<CustomUserResponse[]> callback);

Solution 4

You could try something like this

JSONObject jsonObject = new JSONObject(<your JSON string result>);
JSONArray jsonArray = jsonObject.getJSONArray();

//use GSON to parse
if (jsonArray != null) {
   Gson gson = new Gson();
   ObjResponse[] objResponse = gson.fromJson(jsonArray.toString(), ObjResponse[].class);
   List<ObjResponse> objResponseList = Arrays.asList(objResponse);
}

This should definitely work.

Share:
24,720

Related videos on Youtube

Lion789
Author by

Lion789

Updated on December 19, 2020

Comments

  • Lion789
    Lion789 over 3 years

    I am returning an array of results with my json Objects, and I am trying to use my customObjectResponse class to pull out each of the fields within each of the objects... the problem it is expecting an object so how do I edit my class to allow it to take in an array of object to be able to then call the fields of each object... I am confused as to what needs to be added:

    Here is a response example of what is being passed to be used:

    [
      {
        itemId: 'dfsdfsdf343434',
        name: 'tests',
        picture: '6976-7jv8h5.jpg',
        description: 'testy.',
        dateUpdated: 1395101819,
    
      }
    ]
    

    Here is my response Object Class:

    public class ObjResponse{
        private String itemId;
        private String name;
        private String picture;
    
        private String description;
    
        private String location;
        private int dateUpdated;
    
        private String msg;
    
    
    
    
        //gridview constructor
        public ObjResponse(String picture) {
            this.picture = picture;
        }
    
        //public constructor
        public ObjResponse() {
    
        }
    
        public String getItemId() {
            return itemId;
        }
    
        public void setItemId(String itemId) {
            this.itemId = itemId;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public String getPicture() {
            return picture;
        }
    
        public void setPicture(String picture) {
            this.picture = picture;
        }
    
    
        public String getLocation() {
            return location;
        }
    
        public void setLocation(String location) {
            this.location = location;
        }
    
    
        public String getDescription() {
            return description;
        }
    
        public void setDescription(String description) {
            this.description = description;
        }
    
    
    
        public int getDateUpdated() {
            return dateUpdated;
        }
    
        public void setDateUpdated(int dateUpdated) {
            this.dateUpdated = dateUpdated;
        }
    
    
    
    
        public String getMsg() {
            return msg;
        }
    
    }
    

    what I am trying, but is not working, even if I separate the classes into their own files:

    Data passed in:
    items: [{obj1: "A", obj2: ["c", "d"]}, {etc...}]
    
    
    public class Response {
    
            public class List<Custom> {
                    private List<Custom> items;
            }
    
            public class Custom {
                    private String obj1;
                    private List<Obj2> obj2;
            }
    
            public Class Obj2 {
                    private String letters;
            }
    }
    
  • Lion789
    Lion789 about 10 years
    Where does this go, in terms of my class above? In my Object Response class?
  • VikramV
    VikramV about 10 years
    No, this would be in your calling activity class. The class where you are having your webservice call. My reply would be applicable in the response of that webservice call.
  • Lion789
    Lion789 about 10 years
    From what I understand if I just build the correct hierarchy then gson will take care of it without me having to do anything fancy... I added an example code of what I think might work but does not... I even tried to separate it into separate files
  • Lion789
    Lion789 about 10 years
    I say this because I am using retrofit which handles the gson from what I understand and I need to just specify the right class but having an issue with it
  • VikramV
    VikramV about 10 years
    Ok, how are you getting the JSON response? Are you calling a webservice or something?
  • Lion789
    Lion789 about 10 years
    using retrofit, your response might have been good but I was looking for a way to accept the array in my object, and I realized I just needed to wrap it in a list.
  • VikramV
    VikramV about 10 years
    Actually my code works for me perfectly. What's I do is, call a webservice, in return I get a JSON response. That response is passed to the line JSONObject jsonObject = new JSONObject(<your JSON string result>); And the rest is same. I get the desired list after parsing through gson
  • Terril Thomas
    Terril Thomas almost 10 years
    can you share how did you then use your POJO
  • Lion789
    Lion789 over 9 years
    I am grabbing the info as a list of my custom object and then for each list item, item[0] for example I have all the custom object get/set properties... if that is not what you are referring to than please explain so I can help.
  • Lion789
    Lion789 over 9 years
    Does it make a difference if it is a List vs an Array?
  • gMale
    gMale over 9 years
    Nope. Whichever is more convenient for you should work just fine. Personally, I tend to use Arrays at the lowest level and convert them to Lists only if/when needed (which I find is less often than I expect, at times).
  • IgorGanapolsky
    IgorGanapolsky about 9 years
    What type of object is the Callback?
  • Lion789
    Lion789 almost 9 years
    The Callback is a retrofit function, I am just adding a list of the single objects
  • Shubham A.
    Shubham A. over 8 years
    This solution is actually better. This can be easily modified in case the data returned is not an array of objects directly but JSON Array is contained inside another key.
  • VikramV
    VikramV over 8 years
    @Shubham: Glad my response could help you.
  • Lion789
    Lion789 almost 8 years
    What are you looking for exactly that is the full code the custom object is on top
  • Stoycho Andreev
    Stoycho Andreev almost 8 years
    There is no need for full implementation of the code. The important part here is that if you tell to Retrofit that to parse the server response like List this means that your json at the top level is not json object {} but json array [] .
  • Arpit Patel
    Arpit Patel over 7 years
    can you provide your POJO??
  • Lion789
    Lion789 over 7 years
    @ArpitPatel The ObjResponse because it is listed above or what are you referring to exactly? If you are trying to understand how to grab or make a get you have to loop through the List of items and call a get on each item.